You’ve just created a new Nanoc site. The page you are looking at right now is the home page for your site. To get started, consider replacing this default homepage with your own customized homepage. Some pointers on how to do so:
Change this page’s content by editing the “index.html” file in the “content” directory. This is the actual page content, and therefore doesn’t include the header, sidebar or style information (those are part of the layout).
Change the layout, which is the “default.html” file in the “layouts” directory, and create something unique (and hopefully less bland).
If you need any help with customizing your Nanoc web site, be sure to check out the documentation (see sidebar), and be sure to subscribe to the discussion group (also see sidebar). Enjoy!
EOS DEFAULT_STYLESHEET = <<~EOS unless defined? DEFAULT_STYLESHEET * { margin: 0; padding: 0; font-family: Georgia, Palatino, serif; } body { background: #fff; } a { text-decoration: none; } a:link, a:visited { color: #f30; } a:hover { color: #f90; } #main { position: absolute; top: 40px; left: 280px; width: 500px; } #main h1 { font-size: 40px; font-weight: normal; line-height: 40px; letter-spacing: -1px; } #main p { margin: 20px 0; font-size: 15px; line-height: 20px; } #main ul, #main ol { margin: 20px; } #main li { font-size: 15px; line-height: 20px; } #main ul li { list-style-type: square; } #sidebar { position: absolute; top: 40px; left: 20px; width: 200px; padding: 20px 20px 0 0; border-right: 1px solid #ccc; text-align: right; } #sidebar h2 { text-transform: uppercase; font-size: 13px; color: #333; letter-spacing: 1px; line-height: 20px; } #sidebar ul { list-style-type: none; margin: 20px 0; } #sidebar li { font-size: 14px; line-height: 20px; } EOS DEFAULT_LAYOUT = <<~EOS unless defined? DEFAULT_LAYOUT
return if element.parent.nil?
#
div_inner = Nokogiri::XML::Node.new('div', element.document)
div_inner['class'] = 'code'
div_inner.children = element.dup
#
div_outer = Nokogiri::XML::Node.new('div', element.document)
div_outer['class'] = 'CodeRay'
div_outer.children = div_inner
# orig element
element.swap div_outer
end
end
class PygmentizeColorizer < Abstract
identifier :pygmentize
def process(code, language, params = {})
check_availability('pygmentize', '-V')
params[:encoding] ||= 'utf-8'
params[:nowrap] ||= 'True'
cmd = ['pygmentize', '-l', language, '-f', 'html']
cmd << '-O' << params.map { |k, v| "#{k}=#{v}" }.join(',') unless params.empty?
stdout = StringIO.new
stderr = $stderr
piper = Nanoc::Extra::Piper.new(stdout: stdout, stderr: stderr)
piper.run(cmd, code)
stdout.string
end
end
class PygmentsrbColorizer < Abstract
identifier :pygmentsrb
def process(code, language, params = {})
require 'pygments'
args = params.dup
args[:lexer] ||= language
args[:options] ||= {}
args[:options][:encoding] ||= 'utf-8'
args[:options][:nowrap] ||= 'True'
Pygments.highlight(code, args)
end
end
class SimonHighlightColorizer < Abstract
identifier :simon_highlight
SIMON_HIGHLIGHT_OPT_MAP = {
wrap: '-W',
include_style: '-I',
line_numbers: '-l',
}.freeze
def process(code, language, params = {})
check_availability('highlight', '--version')
cmd = ['highlight', '--syntax', language, '--fragment']
params.each_key do |key|
if SIMON_HIGHLIGHT_OPT_MAP[key]
cmd << SIMON_HIGHLIGHT_OPT_MAP[key]
else
# TODO: allow passing other options
case key
when :style
cmd << '--style' << params[:style]
end
end
end
stdout = StringIO.new
stderr = $stderr
piper = Nanoc::Extra::Piper.new(stdout: stdout, stderr: stderr)
piper.run(cmd, code)
stdout.string
end
end
class RougeColorizer < Abstract
identifier :rouge
def process(code, language, params = {})
require 'rouge'
if params.fetch(:legacy, false)
formatter_options = {
css_class: params.fetch(:css_class, 'highlight'),
inline_theme: params.fetch(:inline_theme, nil),
line_numbers: params.fetch(:line_numbers, false),
start_line: params.fetch(:start_line, 1),
wrap: params.fetch(:wrap, false),
}
formatter_cls = Rouge::Formatters::HTMLLegacy
formatter = formatter_cls.new(formatter_options)
else
formatter = params.fetch(:formatter, Rouge::Formatters::HTML.new)
end
lexer = Rouge::Lexer.find_fancy(language, code) || Rouge::Lexers::PlainText
formatter.format(lexer.lex(code))
end
def postprocess(_language, element)
# Removes the double wrapping.
#
# Before:
#
#
#
# After:
#
#
return if element.name != 'pre'
code1 = element.xpath('code').first
return if code1.nil?
div = code1.xpath('div').first
# For Rouge 2.x and 1.x, respectively
pre = (div || code1).xpath('pre').first
return if pre.nil?
code2 = pre.xpath('code').first
return if code2.nil?
code1.inner_html = code2.inner_html
code1['class'] = [code1['class'], pre['class']].compact.join(' ')
end
end
end
nanoc-4.11.0/nanoc/lib/nanoc/filters/erb.rb000066400000000000000000000020711340050175000203750ustar00rootroot00000000000000# frozen_string_literal: true
module Nanoc::Filters
# @api private
class ERB < Nanoc::Filter
identifier :erb
requires 'erb'
# Runs the content through [ERB](http://ruby-doc.org/stdlib/libdoc/erb/rdoc/classes/ERB.html).
#
# @param [String] content The content to filter
#
# @option params [Integer] :safe_level (nil) The safe level (`$SAFE`) to
# use while running this filter
#
# @option params [String] :trim_mode (nil) The trim mode to use
#
# @return [String] The filtered content
def run(content, params = {})
# Add locals
assigns.merge!(params[:locals] || {})
# Create context
context = ::Nanoc::Int::Context.new(assigns)
# Get binding
proc = assigns[:content] ? -> { assigns[:content] } : nil
assigns_binding = context.get_binding(&proc)
# Get result
safe_level = params[:safe_level]
trim_mode = params[:trim_mode]
erb = ::ERB.new(content, safe_level, trim_mode)
erb.filename = filename
erb.result(assigns_binding)
end
end
end
nanoc-4.11.0/nanoc/lib/nanoc/filters/erubi.rb000066400000000000000000000016631340050175000207410ustar00rootroot00000000000000# frozen_string_literal: true
module Nanoc::Filters
# @api private
class Erubi < Nanoc::Filter
identifier :erubi
requires 'erubi'
# Runs the content through [Erubi](https://github.com/jeremyevans/erubi).
# To prevent single quote escaping use :escapefunc => 'Nanoc::Helpers::HTMLEscape.html_escape'
# See the Erubi documentation for more options.
#
# @param [String] content The content to filter
#
# @return [String] The filtered content
def run(content, params = {})
# Create context
context = ::Nanoc::Int::Context.new(assigns)
# Get binding
proc = assigns[:content] ? -> { assigns[:content] } : nil
assigns_binding = context.get_binding(&proc)
# Get result
engine_opts = { bufvar: '_erbout', filename: filename }.merge(params)
engine = ::Erubi::Engine.new(content, engine_opts)
eval(engine.src, assigns_binding, filename)
end
end
end
nanoc-4.11.0/nanoc/lib/nanoc/filters/erubis.rb000066400000000000000000000015551340050175000211240ustar00rootroot00000000000000# frozen_string_literal: true
module Nanoc::Filters
# @api private
class Erubis < Nanoc::Filter
identifier :erubis
requires 'erubis'
# Runs the content through [Erubis](http://www.kuwata-lab.com/erubis/).
# This method takes no options.
#
# @param [String] content The content to filter
#
# @return [String] The filtered content
def run(content, _params = {})
# Create context
context = ::Nanoc::Int::Context.new(assigns)
# Get binding
proc = assigns[:content] ? -> { assigns[:content] } : nil
assigns_binding = context.get_binding(&proc)
# Get result
erubis_with_erbout.new(content, filename: filename).result(assigns_binding)
end
private
def erubis_with_erbout
@_erubis_with_erbout ||= Class.new(::Erubis::Eruby) { include ::Erubis::ErboutEnhancer }
end
end
end
nanoc-4.11.0/nanoc/lib/nanoc/filters/haml.rb000066400000000000000000000013351340050175000205500ustar00rootroot00000000000000# frozen_string_literal: true
module Nanoc::Filters
# @api private
class Haml < Nanoc::Filter
identifier :haml
requires 'haml'
# Runs the content through [Haml](http://haml-lang.com/).
# Parameters passed to this filter will be passed on to Haml.
#
# @param [String] content The content to filter
#
# @return [String] The filtered content
def run(content, params = {})
# Get options
options = params.merge(filename: filename)
# Create context
context = ::Nanoc::Int::Context.new(assigns)
# Get result
proc = assigns[:content] ? -> { assigns[:content] } : nil
::Haml::Engine.new(content, options).render(context, assigns, &proc)
end
end
end
nanoc-4.11.0/nanoc/lib/nanoc/filters/handlebars.rb000066400000000000000000000015741340050175000217370ustar00rootroot00000000000000# frozen_string_literal: true
module Nanoc::Filters
# @api private
class Handlebars < Nanoc::Filter
identifier :handlebars
requires 'handlebars'
# Runs the content through
# [Handlebars](http://handlebarsjs.com/) using
# [Handlebars.rb](https://github.com/cowboyd/handlebars.rb).
# This method takes no options.
#
# @param [String] content The content to filter
#
# @return [String] The filtered content
def run(content, _params = {})
context = item.attributes.dup
context[:item] = assigns[:item].attributes
context[:config] = assigns[:config]
context[:yield] = assigns[:content]
if assigns.key?(:layout)
context[:layout] = assigns[:layout].attributes
end
handlebars = ::Handlebars::Context.new
template = handlebars.compile(content)
template.call(context)
end
end
end
nanoc-4.11.0/nanoc/lib/nanoc/filters/kramdown.rb000066400000000000000000000017601340050175000214530ustar00rootroot00000000000000# frozen_string_literal: true
module Nanoc::Filters
# @api private
class Kramdown < Nanoc::Filter
identifier :kramdown
requires 'kramdown'
# Runs the content through [Kramdown](http://kramdown.gettalong.org/).
# Parameters passed to this filter will be passed on to Kramdown.
#
# @param [String] content The content to filter
#
# @return [String] The filtered content
def run(content, params = {})
params = params.dup
warning_filters = params.delete(:warning_filters)
document = ::Kramdown::Document.new(content, params)
if warning_filters
r = Regexp.union(warning_filters)
warnings = document.warnings.reject { |warning| r =~ warning }
else
warnings = document.warnings
end
if warnings.any?
$stderr.puts "kramdown warning(s) for #{@item_rep.inspect}"
warnings.each do |warning|
$stderr.puts " #{warning}"
end
end
document.to_html
end
end
end
nanoc-4.11.0/nanoc/lib/nanoc/filters/less.rb000066400000000000000000000045161340050175000206010ustar00rootroot00000000000000# frozen_string_literal: true
module Nanoc::Filters
# @api private
class Less < Nanoc::Filter
identifier :less
requires 'less'
# Runs the content through [LESS](http://lesscss.org/).
# This method takes no options.
#
# @param [String] content The content to filter
#
# @return [String] The filtered content
def run(content, params = {})
# Create dependencies
imported_filenames = imported_filenames_from(content)
imported_items = imported_filenames_to_items(imported_filenames)
depend_on(imported_items)
# Add filename to load path
paths = [File.dirname(@item[:content_filename])]
on_main_fiber do
parser = ::Less::Parser.new(paths: paths)
parser.parse(content).to_css(params)
end
end
def imported_filenames_from(content)
imports = []
imports.concat(content.scan(/^@import\s+(["'])([^\1]+?)\1;/))
imports.concat(content.scan(/^@import\s+url\((["']?)([^)]+?)\1\);/))
imports.map { |i| /\.(less|css)$/.match?(i[1]) ? i[1] : i[1] + '.less' }
end
def imported_filenames_to_items(imported_filenames)
item_dir_path = Pathname.new(@item[:content_filename]).dirname.realpath
cwd = Pathname.pwd # FIXME: ugly (get site dir instead)
imported_filenames.map do |filename|
full_paths = Set.new
imported_pathname = Pathname.new(filename)
full_paths << find_file(imported_pathname, item_dir_path)
full_paths << find_file(imported_pathname, cwd)
# Find matching item
@items.find do |i|
next if i[:content_filename].nil?
item_path = Pathname.new(i[:content_filename]).realpath
full_paths.any? { |fp| fp == item_path }
end
end.compact
end
# @param [Pathname] pathname Pathname of the file to find. Can be relative or absolute.
#
# @param [Pathname] root_pathname Directory pathname from which the search will start.
#
# @return [String, nil] A string containing the full path if a file is found, otherwise nil.
def find_file(pathname, root_pathname)
absolute_pathname =
if pathname.relative?
root_pathname + pathname
else
pathname
end
if absolute_pathname.exist?
absolute_pathname.realpath
else
nil
end
end
end
end
nanoc-4.11.0/nanoc/lib/nanoc/filters/markaby.rb000066400000000000000000000007661340050175000212640ustar00rootroot00000000000000# frozen_string_literal: true
module Nanoc::Filters
# @api private
class Markaby < Nanoc::Filter
identifier :markaby
requires 'markaby'
# Runs the content through [Markaby](http://markaby.github.io/).
# This method takes no options.
#
# @param [String] content The content to filter
#
# @return [String] The filtered content
def run(content, _params = {})
# Get result
::Markaby::Builder.new(assigns).instance_eval(content).to_s
end
end
end
nanoc-4.11.0/nanoc/lib/nanoc/filters/maruku.rb000066400000000000000000000010041340050175000211240ustar00rootroot00000000000000# frozen_string_literal: true
module Nanoc::Filters
# @api private
class Maruku < Nanoc::Filter
identifier :maruku
requires 'maruku'
# Runs the content through [Maruku](https://github.com/bhollis/maruku/).
# Parameters passed to this filter will be passed on to Maruku.
#
# @param [String] content The content to filter
#
# @return [String] The filtered content
def run(content, params = {})
# Get result
::Maruku.new(content, params).to_html
end
end
end
nanoc-4.11.0/nanoc/lib/nanoc/filters/mustache.rb000066400000000000000000000010361340050175000214360ustar00rootroot00000000000000# frozen_string_literal: true
module Nanoc::Filters
# @api private
class Mustache < Nanoc::Filter
identifier :mustache
requires 'mustache'
# Runs the content through
# [Mustache](http://github.com/defunkt/mustache). This method takes no
# options.
#
# @param [String] content The content to filter
#
# @return [String] The filtered content
def run(content, _params = {})
context = item.attributes.merge(yield: assigns[:content])
::Mustache.render(content, context)
end
end
end
nanoc-4.11.0/nanoc/lib/nanoc/filters/pandoc.rb000066400000000000000000000023111340050175000210660ustar00rootroot00000000000000# frozen_string_literal: true
module Nanoc::Filters
# @api private
class Pandoc < Nanoc::Filter
identifier :pandoc
requires 'pandoc-ruby'
# Runs the content through [Pandoc](http://johnmacfarlane.net/pandoc/)
# using [PandocRuby](https://github.com/alphabetum/pandoc-ruby).
#
# Arguments can be passed to PandocRuby in two ways:
#
# * Use the `:args` option. This approach is more flexible, since it
# allows passing an array instead of a hash.
#
# * Pass the arguments directly to the filter. With this approach, only
# hashes can be passed, which is more limiting than the `:args` approach.
#
# The `:args` approach is recommended.
#
# @example Passing arguments using `:arg`
#
# filter :pandoc, args: [:s, {:f => :markdown, :to => :html}, 'wrap=none', :toc]
#
# @example Passing arguments not using `:arg`
#
# filter :pandoc, :f => :markdown, :to => :html
#
# @param [String] content The content to filter
#
# @return [String] The filtered content
def run(content, params = {})
args = params.key?(:args) ? params[:args] : params
PandocRuby.convert(content, *args)
end
end
end
nanoc-4.11.0/nanoc/lib/nanoc/filters/rainpress.rb000066400000000000000000000010011340050175000216230ustar00rootroot00000000000000# frozen_string_literal: true
module Nanoc::Filters
# @api private
class Rainpress < Nanoc::Filter
identifier :rainpress
requires 'rainpress'
# Runs the content through [Rainpress](http://code.google.com/p/rainpress/).
# Parameters passed to this filter will be passed on to Rainpress.
#
# @param [String] content The content to filter
#
# @return [String] The filtered content
def run(content, params = {})
::Rainpress.compress(content, params)
end
end
end
nanoc-4.11.0/nanoc/lib/nanoc/filters/rdiscount.rb000066400000000000000000000011041340050175000216330ustar00rootroot00000000000000# frozen_string_literal: true
module Nanoc::Filters
# @api private
class RDiscount < Nanoc::Filter
identifier :rdiscount
requires 'rdiscount'
# Runs the content through [RDiscount](http://github.com/rtomayko/rdiscount).
#
# @option params [Array] :extensions ([]) A list of RDiscount extensions
#
# @param [String] content The content to filter
#
# @return [String] The filtered content
def run(content, params = {})
extensions = params[:extensions] || []
::RDiscount.new(content, *extensions).to_html
end
end
end
nanoc-4.11.0/nanoc/lib/nanoc/filters/rdoc.rb000066400000000000000000000010761340050175000205600ustar00rootroot00000000000000# frozen_string_literal: true
module Nanoc::Filters
# @api private
class RDoc < Nanoc::Filter
identifier :rdoc
requires 'rdoc'
# Runs the content through [RDoc::Markup](http://docs.seattlerb.org/rdoc/RDoc/Markup.html).
# This method takes no options.
#
# @param [String] content The content to filter
#
# @return [String] The filtered content
def run(content, _params = {})
options = ::RDoc::Options.new
to_html = ::RDoc::Markup::ToHtml.new(options)
::RDoc::Markup.new.convert(content, to_html)
end
end
end
nanoc-4.11.0/nanoc/lib/nanoc/filters/redcarpet.rb000066400000000000000000000024641340050175000216040ustar00rootroot00000000000000# frozen_string_literal: true
module Nanoc::Filters
# @api private
class Redcarpet < Nanoc::Filter
identifier :redcarpet
requires 'redcarpet'
def run(content, params = {})
options = params.fetch(:options, {})
renderer_class = params.fetch(:renderer, ::Redcarpet::Render::HTML)
renderer_options = params.fetch(:renderer_options, {})
with_toc = params.fetch(:with_toc, false)
# Setup TOC
if with_toc
unless renderer_class <= ::Redcarpet::Render::HTML
raise "Unexpected renderer: #{renderer_class}"
end
# `with_toc` implies `with_toc_data` for the HTML renderer
renderer_options[:with_toc_data] = true
end
# Create renderer
renderer =
if renderer_class == ::Redcarpet::Render::HTML_TOC
renderer_class.new
else
renderer_class.new(renderer_options)
end
# Render
if with_toc
renderer_toc = ::Redcarpet::Render::HTML_TOC.new
toc = ::Redcarpet::Markdown.new(renderer_toc, options).render(content)
body = ::Redcarpet::Markdown.new(renderer, options).render(content)
toc + body
else
::Redcarpet::Markdown.new(renderer, options).render(content)
end
end
end
end
nanoc-4.11.0/nanoc/lib/nanoc/filters/redcloth.rb000066400000000000000000000031511340050175000214310ustar00rootroot00000000000000# frozen_string_literal: true
module Nanoc::Filters
# @api private
class RedCloth < Nanoc::Filter
identifier :redcloth
requires 'redcloth'
# Runs the content through [RedCloth](http://redcloth.org/). This method
# takes the following options:
#
# * `:filter_class`
# * `:filter_html`
# * `:filter_ids`
# * `:filter_style`
# * `:hard_breaks`
# * `:lite_mode`
# * `:no_span_caps`
# * `:sanitize_htm`
#
# Each of these options sets the corresponding attribute on the `RedCloth`
# instance. For example, when the `:hard_breaks => false` option is passed
# to this filter, the filter will call `r.hard_breaks = false` (with `r`
# being the `RedCloth` instance).
#
# @param [String] content The content to filter
#
# @return [String] The filtered content
def run(content, params = {})
# Create formatter
r = ::RedCloth.new(content)
# Set options
r.filter_classes = params[:filter_classes] if params.key?(:filter_classes)
r.filter_html = params[:filter_html] if params.key?(:filter_html)
r.filter_ids = params[:filter_ids] if params.key?(:filter_ids)
r.filter_styles = params[:filter_styles] if params.key?(:filter_styles)
r.hard_breaks = params[:hard_breaks] if params.key?(:hard_breaks)
r.lite_mode = params[:lite_mode] if params.key?(:lite_mode)
r.no_span_caps = params[:no_span_caps] if params.key?(:no_span_caps)
r.sanitize_html = params[:sanitize_html] if params.key?(:sanitize_html)
# Get result
r.to_html
end
end
end
nanoc-4.11.0/nanoc/lib/nanoc/filters/relativize_paths.rb000066400000000000000000000135171340050175000232110ustar00rootroot00000000000000# frozen_string_literal: true
module Nanoc::Filters
# @api private
class RelativizePaths < Nanoc::Filter
identifier :relativize_paths
require 'nanoc/helpers/link_to'
include Nanoc::Helpers::LinkTo
DDMemoize.activate(self)
SELECTORS = ['*/@href', '*/@src', 'object/@data', 'param[@name="movie"]/@content', 'form/@action', 'comment()'].freeze
GCSE_SEARCH_WORKAROUND = 'nanoc__gcse_search__f7ac3462f628a053f86fe6563c0ec98f1fe45cee'
# Relativizes all paths in the given content, which can be HTML, XHTML, XML
# or CSS. This filter is quite useful if a site needs to be hosted in a
# subdirectory instead of a subdomain. In HTML, all `href` and `src`
# attributes will be relativized. In CSS, all `url()` references will be
# relativized.
#
# @param [String] content The content to filter
#
# @option params [Symbol] :type The type of content to filter; can be
# `:html`, `:xhtml`, `:xml` or `:css`.
#
# @option params [Array] :select The XPath expressions that matches the
# nodes to modify. This param is useful only for the `:html`, `:xml` and
# `:xhtml` types.
#
# @option params [Hash] :namespaces The pairs `prefix => uri` to define
# any namespace you want to use in the XPath expressions. This param
# is useful only for the `:xml` and `:xhtml` types.
#
# @return [String] The filtered content
def run(content, params = {})
Nanoc::Extra::JRubyNokogiriWarner.check_and_warn
# Set assigns so helper function can be used
@item_rep = assigns[:item_rep] if @item_rep.nil?
# Filter
case params[:type]
when :css
relativize_css(content, params)
when :html, :html5, :xml, :xhtml
relativize_html_like(content, params)
else
raise 'The relativize_paths needs to know the type of content to ' \
'process. Pass a :type to the filter call (:html for HTML, ' \
':xhtml for XHTML, :xml for XML, or :css for CSS).'
end
end
protected
def relativize_css(content, params)
# FIXME: parse CSS the proper way using csspool or something
content.gsub(/url\((['"]?)(\/(?:[^\/].*?)?)\1\)/) do
quote = Regexp.last_match[1]
path = Regexp.last_match[2]
if exclude?(path, params)
Regexp.last_match[0]
else
'url(' + quote + relative_path_to(path) + quote + ')'
end
end
end
memoized def excludes(params)
raw = [params.fetch(:exclude, [])].flatten
raw.map do |exclusion|
case exclusion
when Regexp
exclusion
when String
/\A#{exclusion}(\z|\/)/
end
end
end
def exclude?(path, params)
# TODO: Use #match? on newer Ruby versions
excludes(params).any? { |ex| path =~ ex }
end
def relativize_html_like(content, params)
selectors = params.fetch(:select, SELECTORS)
namespaces = params.fetch(:namespaces, {})
type = params.fetch(:type)
nokogiri_save_options = params.fetch(:nokogiri_save_options, nil)
parser = parser_for(type)
content = fix_content(content, type)
nokogiri_process(content, selectors, namespaces, parser, type, nokogiri_save_options, params)
end
def parser_for(type)
case type
when :html
require 'nokogiri'
::Nokogiri::HTML
when :html5
require 'nokogumbo'
::Nokogiri::HTML5
when :xml
require 'nokogiri'
::Nokogiri::XML
when :xhtml
require 'nokogiri'
::Nokogiri::XML
end
end
def fix_content(content, type)
case type
when :xhtml
# FIXME: cleanup because it is ugly
# this cleans the XHTML namespace to process fragments and full
# documents in the same way. At least, Nokogiri adds this namespace
# if detects the `html` element.
content.sub(%r{(]+)xmlns="http://www.w3.org/1999/xhtml"}, '\1')
else
content
end
end
def nokogiri_process(content, selectors, namespaces, klass, type, nokogiri_save_options, params)
# Ensure that all prefixes are strings
namespaces = namespaces.reduce({}) { |new, (prefix, uri)| new.merge(prefix.to_s => uri) }
content = apply_gcse_search_workaround(content)
doc = /]/.match?(content) ? klass.parse(content) : klass.fragment(content)
selector = selectors.map { |sel| "descendant-or-self::#{sel}" }.join('|')
doc.xpath(selector, namespaces).each do |node|
if node.name == 'comment'
nokogiri_process_comment(node, doc, selectors, namespaces, klass, type, params)
elsif path_is_relativizable?(node.content, params)
node.content = relative_path_to(node.content)
end
end
output =
case type
when :html5
doc.to_html(save_with: nokogiri_save_options)
else
doc.send("to_#{type}", save_with: nokogiri_save_options)
end
revert_gcse_search_workaround(output)
end
def apply_gcse_search_workaround(content)
content.gsub('gcse:search', GCSE_SEARCH_WORKAROUND)
end
def revert_gcse_search_workaround(content)
content.gsub(GCSE_SEARCH_WORKAROUND, 'gcse:search')
end
def nokogiri_process_comment(node, doc, selectors, namespaces, klass, type, params)
content = node.content.dup.sub(%r{^(\s*\[.+?\]>\s*)(.+?)(\s* 'definitely'
#
# @param [String] _content Ignored. As the filter can be run only as a
# layout, the value of the `:content` parameter passed to the class at
# initialization is used as the content to transform.
#
# @param [Hash] params The parameters that will be stored in corresponding
# `xsl:param` elements.
#
# @return [String] The transformed content
def run(_content, params = {})
Nanoc::Extra::JRubyNokogiriWarner.check_and_warn
if assigns[:layout].nil?
raise 'The XSL filter can only be run as a layout'
end
xml = ::Nokogiri::XML(assigns[:content])
xsl = ::Nokogiri::XSLT(assigns[:layout].raw_content)
xsl.apply_to(xml, ::Nokogiri::XSLT.quote_params(params))
end
end
end
nanoc-4.11.0/nanoc/lib/nanoc/filters/yui_compressor.rb000066400000000000000000000012201340050175000227020ustar00rootroot00000000000000# frozen_string_literal: true
module Nanoc::Filters
# @api private
class YUICompressor < Nanoc::Filter
identifier :yui_compressor
requires 'yuicompressor'
# Compress Javascript or CSS using [YUICompressor](http://rubydoc.info/gems/yuicompressor).
# This method optionally takes options to pass directly to the
# YUICompressor gem.
#
# @param [String] content JavaScript or CSS input
#
# @param [Hash] params Options passed to YUICompressor
#
# @return [String] Compressed but equivalent JavaScript or CSS
def run(content, params = {})
::YUICompressor.compress(content, params)
end
end
end
nanoc-4.11.0/nanoc/lib/nanoc/helpers.rb000066400000000000000000000007201340050175000176160ustar00rootroot00000000000000# frozen_string_literal: true
module Nanoc::Helpers
end
require_relative 'helpers/blogging'
require_relative 'helpers/breadcrumbs'
require_relative 'helpers/capturing'
require_relative 'helpers/child_parent'
require_relative 'helpers/filtering'
require_relative 'helpers/html_escape'
require_relative 'helpers/link_to'
require_relative 'helpers/rendering'
require_relative 'helpers/tagging'
require_relative 'helpers/text'
require_relative 'helpers/xml_sitemap'
nanoc-4.11.0/nanoc/lib/nanoc/helpers/000077500000000000000000000000001340050175000172725ustar00rootroot00000000000000nanoc-4.11.0/nanoc/lib/nanoc/helpers/blogging.rb000066400000000000000000000175721340050175000214230ustar00rootroot00000000000000# frozen_string_literal: true
module Nanoc::Helpers
# @see http://nanoc.ws/doc/reference/helpers/#blogging
module Blogging
# @return [Array]
def articles
blk = -> { @items.select { |item| item[:kind] == 'article' } }
if @items.frozen?
@article_items ||= blk.call
else
blk.call
end
end
# @return [Array]
def sorted_articles
blk = -> { articles.sort_by { |a| attribute_to_time(a[:created_at]) }.reverse }
if @items.frozen?
@sorted_article_items ||= blk.call
else
blk.call
end
end
class AtomFeedBuilder
include Nanoc::Helpers::Blogging
attr_accessor :config
attr_accessor :alt_link
attr_accessor :id
attr_accessor :limit
attr_accessor :relevant_articles
attr_accessor :preserve_order
attr_accessor :content_proc
attr_accessor :excerpt_proc
attr_accessor :title_proc
attr_accessor :title
attr_accessor :author_name
attr_accessor :author_uri
attr_accessor :icon
attr_accessor :logo
def initialize(config, item)
@config = config
@item = item
end
def validate
validate_config
validate_feed_item
validate_articles
end
def build
buffer = +''
xml = Builder::XmlMarkup.new(target: buffer, indent: 2)
build_for_feed(xml)
buffer
end
protected
def sorted_relevant_articles
all = relevant_articles
unless @preserve_order
all = all.sort_by { |a| attribute_to_time(a[:created_at]) }
end
all.reverse.first(limit)
end
def last_article
sorted_relevant_articles.first
end
def updated
relevant_articles.map { |a| attribute_to_time(a[:updated_at] || a[:created_at]) }.max
end
def validate_config
if @config[:base_url].nil?
raise Nanoc::Int::Errors::GenericTrivial.new('Cannot build Atom feed: site configuration has no base_url')
end
end
def validate_feed_item
if title.nil?
raise Nanoc::Int::Errors::GenericTrivial.new('Cannot build Atom feed: no title in params, item or site config')
end
if author_name.nil?
raise Nanoc::Int::Errors::GenericTrivial.new('Cannot build Atom feed: no author_name in params, item or site config')
end
if author_uri.nil?
raise Nanoc::Int::Errors::GenericTrivial.new('Cannot build Atom feed: no author_uri in params, item or site config')
end
end
def validate_articles
if relevant_articles.empty?
raise Nanoc::Int::Errors::GenericTrivial.new('Cannot build Atom feed: no articles')
end
if relevant_articles.any? { |a| a[:created_at].nil? }
raise Nanoc::Int::Errors::GenericTrivial.new('Cannot build Atom feed: one or more articles lack created_at')
end
end
def build_for_feed(xml)
root_url = @config[:base_url] + '/'
xml.instruct!
xml.feed(xmlns: 'http://www.w3.org/2005/Atom', 'xml:base' => root_url) do
# Add primary attributes
xml.id(id || root_url)
xml.title title
# Add date
xml.updated(updated.__nanoc_to_iso8601_time)
# Add links
xml.link(rel: 'alternate', href: (alt_link || root_url))
xml.link(rel: 'self', href: feed_url)
# Add author information
xml.author do
xml.name author_name
xml.uri author_uri
end
# Add icon and logo
xml.icon icon if icon
xml.logo logo if logo
# Add articles
sorted_relevant_articles.each do |a|
build_for_article(a, xml)
end
end
end
def build_for_article(article, xml)
# Get URL
url = url_for(article)
return if url.nil?
xml.entry do
# Add primary attributes
xml.id atom_tag_for(article)
xml.title title_proc.call(article), type: 'html'
# Add dates
xml.published attribute_to_time(article[:created_at]).__nanoc_to_iso8601_time
xml.updated attribute_to_time(article[:updated_at] || article[:created_at]).__nanoc_to_iso8601_time
# Add specific author information
if article[:author_name] || article[:author_uri]
xml.author do
xml.name article[:author_name] || author_name
xml.uri article[:author_uri] || author_uri
end
end
# Add link
xml.link(rel: 'alternate', href: url)
# Add content
summary = excerpt_proc.call(article)
xml.content content_proc.call(article), type: 'html'
xml.summary summary, type: 'html' unless summary.nil?
end
end
end
# @option params [Number] :limit
# @option params [Array] :articles
# @option params [Boolean] :preserve_order
# @option params [Proc] :content_proc
# @option params [Proc] :excerpt_proc
# @option params [Proc] :title_proc
# @option params [String] :alt_link
# @option params [String] :id
# @option params [String] :title
# @option params [String] :author_name
# @option params [String] :author_uri
# @option params [String] :icon
# @option params [String] :logo
#
# @return [String]
def atom_feed(params = {})
require 'builder'
# Create builder
builder = AtomFeedBuilder.new(@config, @item)
# Fill builder
builder.alt_link = params[:alt_link]
builder.id = params[:id]
builder.limit = params[:limit] || 5
builder.relevant_articles = params[:articles] || articles || []
builder.preserve_order = params.fetch(:preserve_order, false)
builder.content_proc = params[:content_proc] || ->(a) { a.compiled_content(snapshot: :pre) }
builder.excerpt_proc = params[:excerpt_proc] || ->(a) { a[:excerpt] }
builder.title_proc = params[:title_proc] || ->(a) { a[:title] }
builder.title = params[:title] || @item[:title] || @config[:title]
builder.author_name = params[:author_name] || @item[:author_name] || @config[:author_name]
builder.author_uri = params[:author_uri] || @item[:author_uri] || @config[:author_uri]
builder.icon = params[:icon]
builder.logo = params[:logo]
# Run
builder.validate
builder.build
end
# @return [String]
def url_for(item)
# Check attributes
if @config[:base_url].nil?
raise Nanoc::Int::Errors::GenericTrivial.new('Cannot build Atom feed: site configuration has no base_url')
end
# Build URL
if item[:custom_url_in_feed]
item[:custom_url_in_feed]
elsif item[:custom_path_in_feed]
@config[:base_url] + item[:custom_path_in_feed]
elsif item.path
@config[:base_url] + item.path
end
end
# @return [String]
def feed_url
# Check attributes
if @config[:base_url].nil?
raise Nanoc::Int::Errors::GenericTrivial.new('Cannot build Atom feed: site configuration has no base_url')
end
@item[:feed_url] || @config[:base_url] + @item.path
end
# @return [String]
def atom_tag_for(item)
hostname, base_dir = %r{^.+?://([^/]+)(.*)$}.match(@config[:base_url])[1..2]
formatted_date = attribute_to_time(item[:created_at]).__nanoc_to_iso8601_date
'tag:' + hostname + ',' + formatted_date + ':' + base_dir + (item.path || item.identifier.to_s)
end
# @param [String, Time, Date, DateTime] arg
#
# @return [Time]
def attribute_to_time(arg)
case arg
when DateTime
arg.to_time
when Date
Time.utc(arg.year, arg.month, arg.day)
when String
Time.parse(arg)
else
arg
end
end
end
end
nanoc-4.11.0/nanoc/lib/nanoc/helpers/breadcrumbs.rb000066400000000000000000000111001340050175000221010ustar00rootroot00000000000000# frozen_string_literal: true
module Nanoc::Helpers
# @see http://nanoc.ws/doc/reference/helpers/#breadcrumbs
module Breadcrumbs
class AmbiguousAncestorError < Nanoc::Int::Errors::Generic
def initialize(pattern, items)
@pattern = pattern
@items = items
end
def message
"expected only one item to match #{@pattern}, but found #{@items.size}"
end
end
# @api private
module Int
DEFAULT_TIEBREAKER =
lambda do |items, pattern|
identifiers = items.map(&:identifier).sort
$stderr.puts <<~WARNING
Warning: The breadcrumbs trail (generated by #breadcrumbs_trail) found more than one potential parent item at #{pattern} (found #{identifiers.join(', ')}). Nanoc will pick the first item as the parent. Consider eliminating the ambiguity by making only one item match #{pattern}, or by passing a `:tiebreaker` option to `#breadcrumbs_trail`. (This situation will be an error in the next major version of Nanoc.)
WARNING
items.min_by(&:identifier)
end
ERROR_TIEBREAKER =
lambda do |items, pattern|
raise AmbiguousAncestorError.new(pattern, items)
end
# e.g. unfold(10.class, &:superclass)
# => [Integer, Numeric, Object, BasicObject]
def self.unfold(obj, &blk)
acc = [obj]
res = yield(obj)
if res
acc + unfold(res, &blk)
else
acc
end
end
# e.g. patterns_for_prefix('/foo/1.0')
# => ['/foo/1.0.*', '/foo/1.*']
def self.patterns_for_prefix(prefix)
prefixes =
unfold(prefix) do |old_prefix|
new_prefix = Nanoc::Identifier.new(old_prefix).without_ext
new_prefix == old_prefix ? nil : new_prefix
end
prefixes.map { |pr| pr + '.*' }
end
def self.find_one(items, pat, tiebreaker)
res = items.find_all(pat)
case res.size
when 0
nil
when 1
res.first
else
if tiebreaker.arity == 1
tiebreaker.call(res)
else
tiebreaker.call(res, pat)
end
end
end
end
# @return [Array]
def breadcrumbs_trail(tiebreaker: Int::DEFAULT_TIEBREAKER)
# The design of this function is a little complicated.
#
# We can’t use #parent_of from the ChildParent helper, because the
# breadcrumb trail can have gaps. For example, the breadcrumbs trail for
# /software/oink.md might be /index.md -> nil -> /software/oink.md if
# there is no item matching /software.* or /software/index.*.
#
# What this function does instead is something more complicated:
#
# 1. It creates an ordered prefix list, based on the identifier of the
# item to create a breadcrumbs trail for. For example,
# /software/oink.md might have the prefix list
# ['', '/software', '/software/oink.md'].
#
# 2. For each of the elements in that list, it will create a list of
# patterns could match zero or more items. For example, the element
# '/software' would correspond to the pattern '/software.*'.
#
# 3. For each of the elements in that list, and for each pattern for that
# element, it will find any matching element. For example, the
# pattern '/software.*' (coming from the prefix /software) would match
# the item /software.md.
#
# 4. Return the list of items, with the last element replaced by the item
# for which the breadcrumb is generated for -- while ancestral items
# in the breadcrumbs trail can have a bit of ambiguity, the item for
# which to generate the breadcrumbs trail is fixed.
# e.g. ['', '/foo', '/foo/bar']
components = item.identifier.components
prefixes = components.inject(['']) { |acc, elem| acc + [acc.last + '/' + elem] }
tiebreaker = Int::ERROR_TIEBREAKER if tiebreaker == :error
if @item.identifier.legacy?
prefixes.map { |pr| @items[Nanoc::Identifier.new('/' + pr, type: :legacy)] }
else
ancestral_prefixes = prefixes.reject { |pr| pr =~ /^\/index\./ }[0..-2]
ancestral_items =
ancestral_prefixes.map do |pr|
if pr == ''
@items['/index.*']
else
prefix_patterns = Int.patterns_for_prefix(pr)
prefix_patterns.lazy.map { |pat| Int.find_one(@items, pat, tiebreaker) }.find(&:itself)
end
end
ancestral_items + [item]
end
end
end
end
nanoc-4.11.0/nanoc/lib/nanoc/helpers/capturing.rb000066400000000000000000000120761340050175000216210ustar00rootroot00000000000000# frozen_string_literal: true
module Nanoc::Helpers
# @see http://nanoc.ws/doc/reference/helpers/#capturing
module Capturing
# @api private
class SetContent
include Nanoc::Helpers::Capturing
def initialize(name, params, item)
@name = name
@params = params
@item = item
end
def run(&block)
existing_behavior = @params.fetch(:existing, :error)
# Capture
content_string = capture(&block)
# Get existing contents and prep for store
snapshot_repo = @item._context.snapshot_repo
rep = @item.reps[:default]._unwrap
capture_name = "__capture_#{@name}".to_sym
old_content_string =
case existing_behavior
when :overwrite
''
when :append
c = snapshot_repo.get(rep, capture_name)
c ? c.string : ''
when :error
contents = snapshot_repo.get(rep, capture_name)
if contents && contents.string != content_string
# FIXME: get proper exception
raise "a capture named #{@name.inspect} for #{@item.identifier} already exists"
else
''
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
new_content = Nanoc::Int::TextualContent.new(old_content_string + content_string)
snapshot_repo.set(rep, capture_name, new_content)
end
end
# @api private
class GetContent
def initialize(requested_item, name, item, config)
@requested_item = requested_item
@name = name
@item = item
@config = config
end
def run
rep = @requested_item.reps[:default]._unwrap
# Create dependency
if @item.nil? || @requested_item != @item._unwrap
dependency_tracker = @config._context.dependency_tracker
dependency_tracker.bounce(@requested_item._unwrap, compiled_content: true)
unless rep.compiled?
Fiber.yield(Nanoc::Int::Errors::UnmetDependency.new(rep))
return run
end
end
snapshot_repo = @config._context.snapshot_repo
content = snapshot_repo.get(rep, "__capture_#{@name}".to_sym)
content ? content.string : nil
end
end
# @overload content_for(name, &block)
# @param [Symbol, String] name
# @return [void]
#
# @overload content_for(name, params, &block)
# @param [Symbol, String] name
# @option params [Symbol] existing
# @return [void]
#
# @overload content_for(name, content)
# @param [Symbol, String] name
# @param [String] content
# @return [void]
#
# @overload content_for(name, params, content)
# @param [Symbol, String] name
# @param [String] content
# @option params [Symbol] existing
# @return [void]
#
# @overload content_for(item, name)
# @param [Symbol, String] name
# @return [String]
def content_for(*args, &block)
if block_given? # Set content
name = args[0]
params =
case args.size
when 1
{}
when 2
args[1]
else
raise ArgumentError, 'expected 1 or 2 argument (the name ' \
"of the capture, and optionally params) but got #{args.size} instead"
end
SetContent.new(name, params, @item).run(&block)
elsif args.size > 1 && (args.first.is_a?(Symbol) || args.first.is_a?(String)) # Set content
name = args[0]
content = args.last
params =
case args.size
when 2
{}
when 3
args[1]
else
raise ArgumentError, 'expected 2 or 3 arguments (the name ' \
"of the capture, optionally params, and the content) but got #{args.size} instead"
end
_erbout = +'' # rubocop:disable Lint/UnderscorePrefixedVariableName
SetContent.new(name, params, @item).run { _erbout << content }
else # Get content
if args.size != 2
raise ArgumentError, 'expected 2 arguments (the item ' \
"and the name of the capture) but got #{args.size} instead"
end
requested_item = args[0]
name = args[1]
GetContent.new(requested_item, name, @item, @config).run
end
end
# @return [String]
def capture(&block)
# Get erbout so far
erbout = eval('_erbout', block.binding)
erbout_length = erbout.length
# Execute block
yield
# Get new piece of erbout
erbout_addition = erbout[erbout_length..-1]
# Remove addition
erbout[erbout_length..-1] = +''
# Depending on how the filter outputs, the result might be a
# single string or an array of strings (slim outputs the latter).
erbout_addition = erbout_addition.join('') if erbout_addition.is_a? Array
# Done.
erbout_addition
end
end
end
nanoc-4.11.0/nanoc/lib/nanoc/helpers/child_parent.rb000066400000000000000000000011051340050175000222500ustar00rootroot00000000000000# frozen_string_literal: true
module Nanoc::Helpers
# @see http://nanoc.ws/doc/reference/helpers/#childparent
module ChildParent
def parent_of(item)
if item.identifier.legacy?
item.parent
else
path_without_last_component = item.identifier.to_s.sub(/[^\/]+$/, '').chop
@items[path_without_last_component + '.*']
end
end
def children_of(item)
if item.identifier.legacy?
item.children
else
pattern = item.identifier.without_ext + '/*'
@items.find_all(pattern)
end
end
end
end
nanoc-4.11.0/nanoc/lib/nanoc/helpers/filtering.rb000066400000000000000000000021561340050175000216060ustar00rootroot00000000000000# frozen_string_literal: true
module Nanoc::Helpers
# @see http://nanoc.ws/doc/reference/helpers/#filtering
module Filtering
require 'nanoc/helpers/capturing'
include Nanoc::Helpers::Capturing
# @param [Symbol] filter_name
# @param [Hash] arguments
#
# @return [void]
def filter(filter_name, arguments = {}, &block)
# Capture block
data = capture(&block)
# Find filter
klass = Nanoc::Filter.named!(filter_name)
# Create filter
assigns = {
item: @item,
rep: @rep,
item_rep: @item_rep,
items: @items,
layouts: @layouts,
config: @config,
content: @content,
}
filter = klass.new(assigns)
# Filter captured data
Nanoc::Int::NotificationCenter.post(:filtering_started, @item_rep._unwrap, filter_name)
filtered_data = filter.setup_and_run(data, arguments)
Nanoc::Int::NotificationCenter.post(:filtering_ended, @item_rep._unwrap, filter_name)
# Append filtered data to buffer
buffer = eval('_erbout', block.binding)
buffer << filtered_data
end
end
end
nanoc-4.11.0/nanoc/lib/nanoc/helpers/html_escape.rb000066400000000000000000000021631340050175000221050ustar00rootroot00000000000000# frozen_string_literal: true
module Nanoc::Helpers
# @see http://nanoc.ws/doc/reference/helpers/#filtering
module HTMLEscape
require 'nanoc/helpers/capturing'
include Nanoc::Helpers::Capturing
# @param [String] string
#
# @return [String]
def html_escape(string = nil, &block)
if block_given?
# Capture and escape block
data = capture(&block)
escaped_data = html_escape(data)
# Append filtered data to buffer
buffer = eval('_erbout', block.binding)
buffer << escaped_data
elsif string
unless string.is_a? String
raise ArgumentError, 'The #html_escape or #h function needs either a ' \
"string or a block to HTML-escape, but #{string.class} was given"
end
string
.gsub('&', '&')
.gsub('<', '<')
.gsub('>', '>')
.gsub('"', '"')
else
raise 'The #html_escape or #h function needs either a ' \
'string or a block to HTML-escape, but neither a string nor a block was given'
end
end
alias h html_escape
end
end
nanoc-4.11.0/nanoc/lib/nanoc/helpers/link_to.rb000066400000000000000000000052761340050175000212700ustar00rootroot00000000000000# frozen_string_literal: true
module Nanoc::Helpers
# @see http://nanoc.ws/doc/reference/helpers/#linkto
module LinkTo
require 'nanoc/helpers/html_escape'
include Nanoc::Helpers::HTMLEscape
# @param [String] text
#
# @param [Hash] attributes
#
# @return [String]
def link_to(text, target, attributes = {})
# Find path
path =
case target
when String
target
when Nanoc::CompilationItemView, Nanoc::BasicItemView, Nanoc::BasicItemRepView
raise "Cannot create a link to #{target.inspect} because this target is not outputted (its routing rule returns nil)" if target.path.nil?
target.path
else
raise ArgumentError, "Cannot link to #{target.inspect} (expected a string or an item, not a #{target.class.name})"
end
# Join attributes
attributes = attributes.reduce('') do |memo, (key, value)|
memo + key.to_s + '="' + h(value) + '" '
end
# Create link
"#{text}"
end
# @param [String] text
#
# @param [Hash] attributes
#
# @return [String]
def link_to_unless_current(text, target, attributes = {})
# Find path
path = target.is_a?(String) ? target : target.path
if @item_rep&.path == path
# Create message
"#{text}"
else
link_to(text, target, attributes)
end
end
# @return [String]
def relative_path_to(target)
# Find path
if target.is_a?(String)
path = target
else
path = target.path
if path.nil?
# TODO: get proper error
raise "Cannot get the relative path to #{target.inspect} because this target is not outputted (its routing rule returns nil)"
end
end
# Handle Windows network (UNC) paths
if path.start_with?('//', '\\\\')
return path
end
# Get source and destination paths
dst_path = Pathname.new(path)
if @item_rep.path.nil?
# TODO: get proper error
raise "Cannot get the relative path to #{path} because the current item representation, #{@item_rep.inspect}, is not outputted (its routing rule returns nil)"
end
src_path = Pathname.new(@item_rep.path)
# Calculate the relative path (method depends on whether destination is
# a directory or not).
from = src_path.to_s.end_with?('/') ? src_path : src_path.dirname
relative_path = dst_path.relative_path_from(from).to_s
# Add trailing slash if necessary
if dst_path.to_s.end_with?('/')
relative_path << '/'
end
# Done
relative_path
end
end
end
nanoc-4.11.0/nanoc/lib/nanoc/helpers/rendering.rb000066400000000000000000000037671340050175000216110ustar00rootroot00000000000000# frozen_string_literal: true
module Nanoc::Helpers
# @see http://nanoc.ws/doc/reference/helpers/#rendering
module Rendering
include Nanoc::Helpers::Capturing
# @param [String] identifier
# @param [Hash] other_assigns
#
# @raise [Nanoc::Int::Errors::UnknownLayout]
# @raise [Nanoc::Int::Errors::CannotDetermineFilter]
# @raise [Nanoc::Int::Errors::UnknownFilter]
#
# @return [String, nil]
def render(identifier, other_assigns = {}, &block)
# Find layout
layout_view = @layouts[identifier]
layout_view ||= @layouts[identifier.__nanoc_cleaned_identifier]
raise Nanoc::Int::Errors::UnknownLayout.new(identifier) if layout_view.nil?
layout = layout_view._unwrap
# Visit
dependency_tracker = @config._context.dependency_tracker
dependency_tracker.bounce(layout, raw_content: true)
# Capture content, if any
captured_content = block_given? ? capture(&block) : nil
# Get assigns
assigns = {
content: captured_content,
item: @item,
item_rep: @item_rep,
items: @items,
layout: layout_view,
layouts: @layouts,
config: @config,
}.merge(other_assigns)
# Get filter name
filter_name, filter_args = *@config._context.compilation_context.filter_name_and_args_for_layout(layout)
raise Nanoc::Int::Errors::CannotDetermineFilter.new(layout.identifier) if filter_name.nil?
# Get filter class
filter_class = Nanoc::Filter.named!(filter_name)
# Create filter
filter = filter_class.new(assigns)
# Layout
content = layout.content
arg = content.binary? ? content.filename : content.string
result = filter.setup_and_run(arg, filter_args)
# Append to erbout if we have a block
if block_given?
# Append result and return nothing
erbout = eval('_erbout', block.binding)
erbout << result
''
else
# Return result
result
end
end
end
end
nanoc-4.11.0/nanoc/lib/nanoc/helpers/tagging.rb000066400000000000000000000016671340050175000212510ustar00rootroot00000000000000# frozen_string_literal: true
module Nanoc::Helpers
# @see http://nanoc.ws/doc/reference/helpers/#tagging
module Tagging
require 'nanoc/helpers/html_escape'
include Nanoc::Helpers::HTMLEscape
# @param [String] base_url
# @param [String] none_text
# @param [String] separator
#
# @return [String]
def tags_for(item, base_url: nil, none_text: '(none)', separator: ', ')
if item[:tags].nil? || item[:tags].empty?
none_text
else
item[:tags].map { |tag| base_url ? link_for_tag(tag, base_url) : tag }.join(separator)
end
end
# @param [String] tag
#
# @return [Array]
def items_with_tag(tag)
@items.select { |i| (i[:tags] || []).include?(tag) }
end
# @param [String] tag
# @param [String] base_url
#
# @return [String]
def link_for_tag(tag, base_url)
%(#{h tag})
end
end
end
nanoc-4.11.0/nanoc/lib/nanoc/helpers/text.rb000066400000000000000000000013061340050175000206030ustar00rootroot00000000000000# frozen_string_literal: true
module Nanoc::Helpers
# @see http://nanoc.ws/doc/reference/helpers/#text
module Text
# @param [String] string
# @param [Number] length
# @param [String] omission
#
# @return [String]
def excerptize(string, length: 25, omission: '...')
if string.length > length
excerpt_length = [0, length - omission.length].max
string[0...excerpt_length] + omission
else
string
end
end
# @param [String] string
#
# @return [String]
def strip_html(string)
# FIXME: will need something more sophisticated than this, because it sucks
string.gsub(/<[^>]*(>+|\s*\z)/m, '').strip
end
end
end
nanoc-4.11.0/nanoc/lib/nanoc/helpers/xml_sitemap.rb000066400000000000000000000030231340050175000221370ustar00rootroot00000000000000# frozen_string_literal: true
module Nanoc::Helpers
# @see http://nanoc.ws/doc/reference/helpers/#xmlsitemap
module XMLSitemap
# @option params [Array] :items
# @option params [Proc] :rep_select
#
# @return [String]
def xml_sitemap(params = {})
require 'builder'
# Extract parameters
items = params.fetch(:items) { @items.reject { |i| i[:is_hidden] } }
select_proc = params.fetch(:rep_select, nil)
# Create builder
buffer = +''
xml = Builder::XmlMarkup.new(target: buffer, indent: 2)
# Check for required attributes
if @config[:base_url].nil?
raise 'The Nanoc::Helpers::XMLSitemap helper requires the site configuration to specify the base URL for the site.'
end
# Build sitemap
xml.instruct!
xml.urlset(xmlns: 'http://www.sitemaps.org/schemas/sitemap/0.9') do
# Add item
items.sort_by(&:identifier).each do |item|
reps = item.reps.select(&:path)
reps.select! { |r| select_proc[r] } if select_proc
reps.sort_by { |r| r.name.to_s }.each do |rep|
xml.url do
xml.loc Addressable::URI.escape(@config[:base_url] + rep.path)
xml.lastmod item[:mtime].__nanoc_to_iso8601_date unless item[:mtime].nil?
xml.changefreq item[:changefreq] unless item[:changefreq].nil?
xml.priority item[:priority] unless item[:priority].nil?
end
end
end
end
# Return sitemap
buffer
end
end
end
nanoc-4.11.0/nanoc/lib/nanoc/rule_dsl.rb000066400000000000000000000011571340050175000177720ustar00rootroot00000000000000# frozen_string_literal: true
module Nanoc
# @api private
module RuleDSL
end
end
require_relative 'rule_dsl/compiler_dsl'
require_relative 'rule_dsl/action_provider'
require_relative 'rule_dsl/action_recorder'
require_relative 'rule_dsl/action_sequence_calculator'
require_relative 'rule_dsl/rules_collection'
require_relative 'rule_dsl/rules_loader'
require_relative 'rule_dsl/rule_context'
require_relative 'rule_dsl/compilation_rule_context'
require_relative 'rule_dsl/routing_rule_context'
require_relative 'rule_dsl/rule'
require_relative 'rule_dsl/compilation_rule'
require_relative 'rule_dsl/routing_rule'
nanoc-4.11.0/nanoc/lib/nanoc/rule_dsl/000077500000000000000000000000001340050175000174415ustar00rootroot00000000000000nanoc-4.11.0/nanoc/lib/nanoc/rule_dsl/action_provider.rb000066400000000000000000000055001340050175000231550ustar00rootroot00000000000000# frozen_string_literal: true
module Nanoc::RuleDSL
class ActionProvider < Nanoc::Int::ActionProvider
identifier :rule_dsl
# @api private
attr_reader :rules_collection
def self.for(site)
rules_collection = Nanoc::RuleDSL::RulesCollection.new
action_sequence_calculator =
Nanoc::RuleDSL::ActionSequenceCalculator.new(
rules_collection: rules_collection, site: site,
)
action_provider = new(rules_collection, action_sequence_calculator)
Nanoc::RuleDSL::RulesLoader.new(site.config, rules_collection).load
action_provider
end
def initialize(rules_collection, action_sequence_calculator)
@rules_collection = rules_collection
@action_sequence_calculator = action_sequence_calculator
end
def rep_names_for(item)
matching_rules = @rules_collection.item_compilation_rules_for(item)
raise Nanoc::Int::Errors::NoMatchingCompilationRuleFound.new(item) if matching_rules.empty?
matching_rules.map(&:rep_name).uniq
end
def action_sequence_for(obj)
@action_sequence_calculator[obj]
end
def need_preprocessing?
@rules_collection.preprocessors.any?
end
def preprocess(site)
ctx = new_preprocessor_context(site)
@rules_collection.preprocessors.each_value do |preprocessor|
ctx.instance_eval(&preprocessor)
end
site.data_source =
Nanoc::Int::InMemDataSource.new(ctx.items._unwrap, ctx.layouts._unwrap, site.data_source)
end
def postprocess(site, compiler)
dependency_tracker = Nanoc::Int::DependencyTracker::Null.new
res = compiler.run_until_reps_built
reps = res.fetch(:reps)
view_context =
Nanoc::ViewContextForCompilation.new(
reps: reps,
items: site.items,
dependency_tracker: dependency_tracker,
compilation_context: compiler.compilation_context(reps: reps),
snapshot_repo: nil,
)
ctx = new_postprocessor_context(site, view_context)
@rules_collection.postprocessors.each_value do |postprocessor|
ctx.instance_eval(&postprocessor)
end
end
# @api private
def new_preprocessor_context(site)
view_context =
Nanoc::ViewContextForPreCompilation.new(items: site.items)
Nanoc::Int::Context.new(
config: Nanoc::MutableConfigView.new(site.config, view_context),
items: Nanoc::MutableItemCollectionView.new(site.items, view_context),
layouts: Nanoc::MutableLayoutCollectionView.new(site.layouts, view_context),
)
end
# @api private
def new_postprocessor_context(site, view_context)
Nanoc::Int::Context.new(
config: Nanoc::ConfigView.new(site.config, view_context),
items: Nanoc::PostCompileItemCollectionView.new(site.items, view_context),
)
end
end
end
nanoc-4.11.0/nanoc/lib/nanoc/rule_dsl/action_recorder.rb000066400000000000000000000044711340050175000231360ustar00rootroot00000000000000# frozen_string_literal: true
module Nanoc
module RuleDSL
class ActionRecorder
include Nanoc::Int::ContractsSupport
contract Nanoc::Int::ItemRep => C::Any
def initialize(rep)
@action_sequence_builder = Nanoc::Int::ActionSequenceBuilder.new(rep)
@any_layouts = false
@last_snapshot = false
@pre_snapshot = false
@snapshots_for_which_to_skip_routing_rule = Set.new
end
def inspect
"<#{self.class}>"
end
def filter(filter_name, filter_args = {})
@action_sequence_builder.add_filter(filter_name, filter_args)
end
def layout(layout_identifier, extra_filter_args = {})
unless layout_identifier.is_a?(String)
raise ArgumentError.new('The layout passed to #layout must be a string')
end
unless any_layouts?
@pre_snapshot = true
@action_sequence_builder.add_snapshot(:pre, nil)
end
@action_sequence_builder.add_layout(layout_identifier, extra_filter_args)
@any_layouts = true
end
MaybePathlike = C::Or[nil, Nanoc::UNDEFINED, String, Nanoc::Identifier]
contract Symbol, C::KeywordArgs[path: C::Optional[MaybePathlike]] => nil
def snapshot(snapshot_name, path: Nanoc::UNDEFINED)
unless Nanoc::UNDEFINED.equal?(path)
@snapshots_for_which_to_skip_routing_rule << snapshot_name
end
path =
if Nanoc::UNDEFINED.equal?(path) || path.nil?
nil
else
path.to_s
end
@action_sequence_builder.add_snapshot(snapshot_name, path)
case snapshot_name
when :last
@last_snapshot = true
when :pre
@pre_snapshot = true
end
nil
end
contract C::None => Nanoc::Int::ActionSequence
def action_sequence
@action_sequence_builder.action_sequence
end
contract C::None => C::Bool
def any_layouts?
@any_layouts
end
contract C::None => Set
def snapshots_for_which_to_skip_routing_rule
@snapshots_for_which_to_skip_routing_rule
end
contract C::None => C::Bool
def last_snapshot?
@last_snapshot
end
contract C::None => C::Bool
def pre_snapshot?
@pre_snapshot
end
end
end
end
nanoc-4.11.0/nanoc/lib/nanoc/rule_dsl/action_sequence_calculator.rb000066400000000000000000000115141340050175000253460ustar00rootroot00000000000000# frozen_string_literal: true
module Nanoc::RuleDSL
class ActionSequenceCalculator
DDMemoize.activate(self)
class UnsupportedObjectTypeException < ::Nanoc::Error
def initialize(obj)
super("Do not know how to calculate the action sequence for #{obj.inspect}")
end
end
class NoActionSequenceForLayoutException < ::Nanoc::Error
def initialize(layout)
super("There is no layout rule specified for #{layout.inspect}")
end
end
class NoActionSequenceForItemRepException < ::Nanoc::Error
def initialize(item)
super("There is no compilation rule specified for #{item.inspect}")
end
end
class PathWithoutInitialSlashError < ::Nanoc::Error
def initialize(rep, basic_path)
super("The path returned for the #{rep.inspect} item representation, “#{basic_path}”, does not start with a slash. Please ensure that all routing rules return a path that starts with a slash.")
end
end
# @api private
attr_accessor :rules_collection
# @param [Nanoc::Int::Site] site
# @param [Nanoc::RuleDSL::RulesCollection] rules_collection
def initialize(site:, rules_collection:)
@site = site
@rules_collection = rules_collection
end
# @param [#reference] obj
#
# @return [Nanoc::Int::ActionSequence]
def [](obj)
case obj
when Nanoc::Int::ItemRep
new_action_sequence_for_rep(obj)
when Nanoc::Int::Layout
new_action_sequence_for_layout(obj)
else
raise UnsupportedObjectTypeException.new(obj)
end
end
def new_action_sequence_for_rep(rep)
view_context =
Nanoc::ViewContextForPreCompilation.new(items: @site.items)
recorder = Nanoc::RuleDSL::ActionRecorder.new(rep)
rule = @rules_collection.compilation_rule_for(rep)
unless rule
raise NoActionSequenceForItemRepException.new(rep)
end
recorder.snapshot(:raw)
rule.apply_to(rep, recorder: recorder, site: @site, view_context: view_context)
recorder.snapshot(:post) if recorder.any_layouts?
recorder.snapshot(:last) unless recorder.last_snapshot?
recorder.snapshot(:pre) unless recorder.pre_snapshot?
copy_paths_from_routing_rules(
compact_snapshots(recorder.action_sequence),
recorder.snapshots_for_which_to_skip_routing_rule,
rep: rep,
)
end
# @param [Nanoc::Int::Layout] layout
#
# @return [Nanoc::Int::ActionSequence]
def new_action_sequence_for_layout(layout)
res = @rules_collection.filter_for_layout(layout)
unless res
raise NoActionSequenceForLayoutException.new(layout)
end
Nanoc::Int::ActionSequence.build(layout) do |b|
b.add_filter(res[0], res[1])
end
end
def compact_snapshots(seq)
actions = []
seq.actions.each do |action|
if [actions.last, action].all? { |a| a.is_a?(Nanoc::Int::ProcessingActions::Snapshot) }
actions[-1] = actions.last.update(snapshot_names: action.snapshot_names, paths: action.paths)
else
actions << action
end
end
Nanoc::Int::ActionSequence.new(seq.item_rep, actions: actions)
end
def copy_paths_from_routing_rules(seq, snapshots_for_which_to_skip_routing_rule, rep:)
# NOTE: This assumes that `seq` is compacted, i.e. there are no two consecutive snapshot actions.
seq.map do |action|
# Only potentially modify snapshot actions
next action unless action.is_a?(Nanoc::Int::ProcessingActions::Snapshot)
# If any of the action’s snapshot are explicitly marked as excluded from
# getting a path from a routing rule, then ignore routing rules.
next action if snapshots_for_which_to_skip_routing_rule.intersect?(Set.new(action.snapshot_names))
# If this action already has paths that don’t come from routing rules,
# then don’t add more to them.
next action unless action.paths.empty?
# For each snapshot name, find a path from a routing rule. The routing
# rule might return nil, so we need #compact.
paths = action.snapshot_names.map { |sn| basic_path_from_rules_for(rep, sn) }.compact
action.update(snapshot_names: [], paths: paths)
end
end
# FIXME: ugly
def basic_path_from_rules_for(rep, snapshot_name)
routing_rules = @rules_collection.routing_rules_for(rep)
routing_rule = routing_rules[snapshot_name]
return nil if routing_rule.nil?
view_context =
Nanoc::ViewContextForPreCompilation.new(items: @site.items)
basic_path =
routing_rule.apply_to(
rep,
site: @site,
view_context: view_context,
)
if basic_path && !basic_path.start_with?('/')
raise PathWithoutInitialSlashError.new(rep, basic_path)
end
basic_path
end
end
end
nanoc-4.11.0/nanoc/lib/nanoc/rule_dsl/compilation_rule.rb000066400000000000000000000011761340050175000233400ustar00rootroot00000000000000# frozen_string_literal: true
module Nanoc::RuleDSL
class CompilationRule < Rule
include Nanoc::Int::ContractsSupport
contract Nanoc::Int::ItemRep, C::KeywordArgs[
site: Nanoc::Int::Site,
recorder: Nanoc::RuleDSL::ActionRecorder,
view_context: Nanoc::ViewContextForPreCompilation,
] => C::Any
def apply_to(rep, site:, recorder:, view_context:)
context = Nanoc::RuleDSL::CompilationRuleContext.new(
rep: rep,
recorder: recorder,
site: site,
view_context: view_context,
)
context.instance_exec(matches(rep.item.identifier), &@block)
end
end
end
nanoc-4.11.0/nanoc/lib/nanoc/rule_dsl/compilation_rule_context.rb000066400000000000000000000054141340050175000251030ustar00rootroot00000000000000# frozen_string_literal: true
module Nanoc::RuleDSL
class CompilationRuleContext < RuleContext
include Nanoc::Int::ContractsSupport
contract C::KeywordArgs[
rep: Nanoc::Int::ItemRep,
site: Nanoc::Int::Site,
recorder: Nanoc::RuleDSL::ActionRecorder,
view_context: Nanoc::ViewContextForPreCompilation,
] => C::Any
def initialize(rep:, site:, recorder:, view_context:)
@_recorder = recorder
super(rep: rep, site: site, view_context: view_context)
end
# Filters the current representation (calls {Nanoc::Int::ItemRep#filter} with
# the given arguments on the rep).
#
# @see Nanoc::Int::ItemRep#filter
#
# @param [Symbol] filter_name The name of the filter to run the item
# representations' content through
#
# @param [Hash] filter_args The filter arguments that should be passed to
# the filter's #run method
#
# @return [void]
def filter(filter_name, filter_args = {})
@_recorder.filter(filter_name, filter_args)
end
# Layouts the current representation (calls {Nanoc::Int::ItemRep#layout} with
# the given arguments on the rep).
#
# @see Nanoc::Int::ItemRep#layout
#
# @param [String] layout_identifier The identifier of the layout the item
# should be laid out with
#
# @return [void]
def layout(layout_identifier, extra_filter_args = nil)
@_recorder.layout(layout_identifier, extra_filter_args)
end
# Creates a snapshot of the current compiled item content. Calls
# {Nanoc::Int::ItemRep#snapshot} with the given arguments on the rep.
#
# @see Nanoc::Int::ItemRep#snapshot
#
# @param [Symbol] snapshot_name The name of the snapshot to create
#
# @param [String, nil] path
#
# @return [void]
def snapshot(snapshot_name, path: Nanoc::UNDEFINED)
@_recorder.snapshot(snapshot_name, path: path)
end
# Creates a snapshot named :last the current compiled item content, with
# the given path. This is a convenience method for {#snapshot}.
#
# @see #snapshot
#
# @param [String] arg
#
# @return [void]
def write(arg)
@_write_snapshot_counter ||= 0
snapshot_name = "_#{@_write_snapshot_counter}".to_sym
@_write_snapshot_counter += 1
case arg
when String, Nanoc::Identifier, nil
snapshot(snapshot_name, path: arg)
when Hash
if arg.key?(:ext)
ext = arg[:ext].sub(/\A\./, '')
path = @item.identifier.without_exts + '.' + ext
snapshot(snapshot_name, path: path)
else
raise ArgumentError, 'Cannot call #write this way (need path or :ext)'
end
else
raise ArgumentError, 'Cannot call #write this way (need path or :ext)'
end
end
end
end
nanoc-4.11.0/nanoc/lib/nanoc/rule_dsl/compiler_dsl.rb000066400000000000000000000254441340050175000224530ustar00rootroot00000000000000# frozen_string_literal: true
module Nanoc::RuleDSL
class CompilerDSL < Nanoc::Int::Context
# The current rules filename.
#
# @return [String] The current rules filename.
#
# @api private
attr_accessor :rules_filename
# Creates a new compiler DSL for the given collection of rules.
#
# @api private
#
# @param [Nanoc::RuleDSL::RulesCollection] rules_collection The collection of
# rules to modify when loading this DSL
#
# @param [Hash] config The site configuration
def initialize(rules_collection, config)
@rules_collection = rules_collection
@config = config
super({ config: config })
end
# Creates a preprocessor block that will be executed after all data is
# loaded, but before the site is compiled.
#
# @yield The block that will be executed before site compilation starts
#
# @return [void]
def preprocess(&block)
if @rules_collection.preprocessors[rules_filename]
warn 'WARNING: A preprocess block is already defined. Defining ' \
'another preprocess block overrides the previously one.'
end
@rules_collection.preprocessors[rules_filename] = block
end
# Creates a compilation rule for all items whose identifier match the
# given identifier, which may either be a string containing the *
# wildcard, or a regular expression.
#
# This rule will be applicable to reps with a name equal to `:default`;
# this can be changed by giving an explicit `:rep` parameter.
#
# An item rep will be compiled by calling the given block and passing the
# rep as a block argument.
#
# @param [String] identifier A pattern matching identifiers of items that
# should be compiled using this rule
#
# @param [Symbol] rep The name of the representation
#
# @yield The block that will be executed when an item matching this
# compilation rule needs to be compiled
#
# @return [void]
#
# @example Compiling the default rep of the `/foo/` item
#
# compile '/foo/' do
# rep.filter :erb
# end
#
# @example Compiling the `:raw` rep of the `/bar/` item
#
# compile '/bar/', :rep => :raw do
# # do nothing
# end
def compile(identifier, rep: :default, &block)
raise ArgumentError.new('#compile requires a block') unless block_given?
rule = Nanoc::RuleDSL::CompilationRule.new(create_pattern(identifier), rep, block)
@rules_collection.add_item_compilation_rule(rule)
end
# Creates a routing rule for all items whose identifier match the
# given identifier, which may either be a string containing the `*`
# wildcard, or a regular expression.
#
# This rule will be applicable to reps with a name equal to `:default`;
# this can be changed by giving an explicit `:rep` parameter.
#
# The path of an item rep will be determined by calling the given block
# and passing the rep as a block argument.
#
# @param [String] identifier A pattern matching identifiers of items that
# should be routed using this rule
#
# @param [Symbol] rep The name of the representation
#
# @param [Symbol] snapshot The name of the snapshot
#
# @yield The block that will be executed when an item matching this
# compilation rule needs to be routed
#
# @return [void]
#
# @example Routing the default rep of the `/foo/` item
#
# route '/foo/' do
# item.identifier + 'index.html'
# end
#
# @example Routing the `:raw` rep of the `/bar/` item
#
# route '/bar/', :rep => :raw do
# '/raw' + item.identifier + 'index.txt'
# end
def route(identifier, rep: :default, snapshot: :last, &block)
raise ArgumentError.new('#route requires a block') unless block_given?
rule = Nanoc::RuleDSL::RoutingRule.new(create_pattern(identifier), rep, block, snapshot_name: snapshot)
@rules_collection.add_item_routing_rule(rule)
end
# Creates a layout rule for all layouts whose identifier match the given
# identifier, which may either be a string containing the * wildcard, or a
# regular expression. The layouts matching the identifier will be filtered
# using the filter specified in the second argument. The params hash
# contains filter arguments that will be passed to the filter.
#
# @param [String] identifier A pattern matching identifiers of layouts
# that should be filtered using this rule
#
# @param [Symbol] filter_name The name of the filter that should be run
# when processing the layout
#
# @param [Hash] params Extra filter arguments that should be passed to the
# filter when processing the layout (see {Nanoc::Filter#run})
#
# @return [void]
#
# @example Specifying the filter to use for a layout
#
# layout '/default/', :erb
#
# @example Using custom filter arguments for a layout
#
# layout '/custom/', :haml, :format => :html5
def layout(identifier, filter_name, params = {})
pattern = Nanoc::Int::Pattern.from(create_pattern(identifier))
@rules_collection.layout_filter_mapping[pattern] = [filter_name, params]
end
# Creates a pair of compilation and routing rules that indicate that the
# specified item(s) should be copied to the output folder as-is. The items
# are selected using an identifier, which may either be a string
# containing the `*` wildcard, or a regular expression.
#
# This meta-rule will be applicable to reps with a name equal to
# `:default`; this can be changed by giving an explicit `:rep` parameter.
#
# @param [String] identifier A pattern matching identifiers of items that
# should be processed using this meta-rule
#
# @param [Symbol] rep The name of the representation
#
# @return [void]
#
# @example Copying the `/foo/` item as-is
#
# passthrough '/foo/'
#
# @example Copying the `:raw` rep of the `/bar/` item as-is
#
# passthrough '/bar/', :rep => :raw
def passthrough(identifier, rep: :default)
raise ArgumentError.new('#passthrough does not require a block') if block_given?
compilation_block = proc {}
compilation_rule = Nanoc::RuleDSL::CompilationRule.new(create_pattern(identifier), rep, compilation_block)
@rules_collection.add_item_compilation_rule(compilation_rule)
# Create routing rule
routing_block = proc do
if item.identifier.full?
item.identifier.to_s
else
# This is a temporary solution until an item can map back to its data
# source.
# ATM item[:content_filename] is nil for items coming from the static
# data source.
item[:extension].nil? || (item[:content_filename].nil? && item.identifier =~ %r{#{item[:extension]}/$}) ? item.identifier.chop : item.identifier.chop + '.' + item[:extension]
end
end
routing_rule = Nanoc::RuleDSL::RoutingRule.new(create_pattern(identifier), rep, routing_block, snapshot_name: :last)
@rules_collection.add_item_routing_rule(routing_rule)
end
# Creates a pair of compilation and routing rules that indicate that the
# specified item(s) should be ignored, e.g. compiled and routed with an
# empty rule. The items are selected using an identifier, which may either
# be a string containing the `*` wildcard, or a regular expression.
#
# This meta-rule will be applicable to reps with a name equal to
# `:default`; this can be changed by giving an explicit `:rep` parameter.
#
# @param [String] identifier A pattern matching identifiers of items that
# should be processed using this meta-rule
#
# @param [Symbol] rep The name of the representation
#
# @return [void]
#
# @example Suppressing compilation and output for all all `/foo/*` items.
#
# ignore '/foo/*'
def ignore(identifier, rep: :default)
raise ArgumentError.new('#ignore does not require a block') if block_given?
compilation_rule = Nanoc::RuleDSL::CompilationRule.new(create_pattern(identifier), rep, proc {})
@rules_collection.add_item_compilation_rule(compilation_rule)
routing_rule = Nanoc::RuleDSL::RoutingRule.new(create_pattern(identifier), rep, proc {}, snapshot_name: :last)
@rules_collection.add_item_routing_rule(routing_rule)
end
# Includes an additional rules file in the current rules collection.
#
# @param [String] name The name of the rules file — an ".rb" extension is
# implied if not explicitly given
#
# @return [void]
#
# @example Including two additional rules files, 'rules/assets.rb' and
# 'rules/content.rb'
#
# include_rules 'rules/assets'
# include_rules 'rules/content'
def include_rules(name)
filename = [name.to_s, "#{name}.rb", "./#{name}", "./#{name}.rb"].find { |f| File.file?(f) }
raise Nanoc::Int::Errors::NoRulesFileFound.new if filename.nil?
Nanoc::RuleDSL::RulesLoader.new(@config, @rules_collection).parse(filename)
end
# Creates a postprocessor block that will be executed after all data is
# loaded and the site is compiled.
#
# @yield The block that will be executed after site compilation completes
#
# @return [void]
def postprocess(&block)
if @rules_collection.postprocessors[rules_filename]
warn 'WARNING: A postprocess block is already defined. Defining ' \
'another postprocess block overrides the previously one.'
end
@rules_collection.postprocessors[rules_filename] = block
end
# @api private
def create_pattern(arg)
case @config[:string_pattern_type]
when 'glob'
Nanoc::Int::Pattern.from(arg)
when 'legacy'
Nanoc::Int::Pattern.from(identifier_to_regex(arg))
else
raise(
Nanoc::Int::Errors::GenericTrivial,
"Invalid string_pattern_type: #{@config[:string_pattern_type]}",
)
end
end
private
# Converts the given identifier, which can contain the '*' or '+'
# wildcard characters, matching zero or more resp. one or more
# characters, to a regex. For example, 'foo/*/bar' is transformed
# into /^foo\/(.*?)\/bar$/ and 'foo+' is transformed into /^foo(.+?)/.
def identifier_to_regex(identifier)
if identifier.is_a? String
# Add leading/trailing slashes if necessary
new_identifier = identifier.dup
new_identifier[/^/] = '/' if identifier[0, 1] != '/'
new_identifier[/$/] = '/?' unless ['*', '/'].include?(identifier[-1, 1])
regex_string =
new_identifier
.gsub('.', '\.')
.gsub('*', '(.*?)')
.gsub('+', '(.+?)')
/^#{regex_string}$/
else
identifier
end
end
end
end
nanoc-4.11.0/nanoc/lib/nanoc/rule_dsl/routing_rule.rb000066400000000000000000000015331340050175000225060ustar00rootroot00000000000000# frozen_string_literal: true
module Nanoc::RuleDSL
class RoutingRule < Rule
include Nanoc::Int::ContractsSupport
contract C::None => C::Maybe[Symbol]
attr_reader :snapshot_name
contract Nanoc::Int::Pattern, Symbol, Proc, C::KeywordArgs[snapshot_name: C::Optional[Symbol]] => C::Any
def initialize(pattern, rep_name, block, snapshot_name: nil)
super(pattern, rep_name, block)
@snapshot_name = snapshot_name
end
contract Nanoc::Int::ItemRep, C::KeywordArgs[
site: Nanoc::Int::Site,
view_context: Nanoc::ViewContextForPreCompilation,
] => C::Any
def apply_to(rep, site:, view_context:)
context = Nanoc::RuleDSL::RoutingRuleContext.new(
rep: rep, site: site, view_context: view_context,
)
context.instance_exec(matches(rep.item.identifier), &@block)
end
end
end
nanoc-4.11.0/nanoc/lib/nanoc/rule_dsl/routing_rule_context.rb000066400000000000000000000001501340050175000242440ustar00rootroot00000000000000# frozen_string_literal: true
module Nanoc::RuleDSL
class RoutingRuleContext < RuleContext
end
end
nanoc-4.11.0/nanoc/lib/nanoc/rule_dsl/rule.rb000066400000000000000000000013071340050175000207360ustar00rootroot00000000000000# frozen_string_literal: true
module Nanoc::RuleDSL
class Rule
include Nanoc::Int::ContractsSupport
contract C::None => Symbol
attr_reader :rep_name
contract C::None => Nanoc::Int::Pattern
attr_reader :pattern
contract Nanoc::Int::Pattern, Symbol, Proc => C::Any
def initialize(pattern, rep_name, block)
@pattern = pattern
@rep_name = rep_name.to_sym
@block = block
end
contract Nanoc::Int::Item => C::Bool
def applicable_to?(item)
@pattern.match?(item.identifier)
end
# @api private
contract Nanoc::Identifier => C::Or[nil, C::ArrayOf[String]]
def matches(identifier)
@pattern.captures(identifier)
end
end
end
nanoc-4.11.0/nanoc/lib/nanoc/rule_dsl/rule_context.rb000066400000000000000000000014471340050175000225070ustar00rootroot00000000000000# frozen_string_literal: true
module Nanoc::RuleDSL
class RuleContext < Nanoc::Int::Context
include Nanoc::Int::ContractsSupport
contract C::KeywordArgs[
rep: Nanoc::Int::ItemRep,
site: Nanoc::Int::Site,
view_context: Nanoc::ViewContextForPreCompilation,
] => C::Any
def initialize(rep:, site:, view_context:)
super({
item: Nanoc::BasicItemView.new(rep.item, view_context),
rep: Nanoc::BasicItemRepView.new(rep, view_context),
item_rep: Nanoc::BasicItemRepView.new(rep, view_context),
items: Nanoc::ItemCollectionWithoutRepsView.new(site.items, view_context),
layouts: Nanoc::LayoutCollectionView.new(site.layouts, view_context),
config: Nanoc::ConfigView.new(site.config, view_context),
})
end
end
end
nanoc-4.11.0/nanoc/lib/nanoc/rule_dsl/rules_collection.rb000066400000000000000000000077221340050175000233430ustar00rootroot00000000000000# frozen_string_literal: true
module Nanoc::RuleDSL
# Keeps track of the rules in a site.
#
# @api private
class RulesCollection
# @return [String] the contents of the Rules file
attr_accessor :data
# The hash containing layout-to-filter mapping rules. This hash is
# ordered: iterating over the hash will happen in insertion order.
#
# @return [Hash] The layout-to-filter mapping rules
attr_reader :layout_filter_mapping
# The hash containing preprocessor code blocks that will be executed after
# all data is loaded but before the site is compiled.
#
# @return [Hash] The hash containing the preprocessor code blocks that will
# be executed after all data is loaded but before the site is compiled
attr_accessor :preprocessors
# The hash containing postprocessor code blocks that will be executed after
# all data is loaded and the site is compiled.
#
# @return [Hash] The hash containing the postprocessor code blocks that will
# be executed after all data is loaded and the site is compiled
attr_accessor :postprocessors
def initialize
@item_compilation_rules = []
@item_routing_rules = []
@layout_filter_mapping = {}
@preprocessors = {}
@postprocessors = {}
end
# Add the given rule to the list of item compilation rules.
#
# @param [Nanoc::Int::Rule] rule The item compilation rule to add
#
# @return [void]
def add_item_compilation_rule(rule)
@item_compilation_rules << rule
end
# Add the given rule to the list of item routing rules.
#
# @param [Nanoc::Int::Rule] rule The item routing rule to add
#
# @return [void]
def add_item_routing_rule(rule)
@item_routing_rules << rule
end
# @param [Nanoc::Int::Item] item The item for which the compilation rules
# should be retrieved
#
# @return [Array] The list of item compilation rules for the given item
def item_compilation_rules_for(item)
@item_compilation_rules.select { |r| r.applicable_to?(item) }
end
# Finds the first matching compilation rule for the given item
# representation.
#
# @param [Nanoc::Int::ItemRep] rep The item rep for which to fetch the rule
#
# @return [Nanoc::Int::Rule, nil] The compilation rule for the given item rep,
# or nil if no rules have been found
def compilation_rule_for(rep)
@item_compilation_rules.find do |rule|
rule.applicable_to?(rep.item) && rule.rep_name == rep.name
end
end
# Returns the list of routing rules that can be applied to the given item
# representation. For each snapshot, the first matching rule will be
# returned. The result is a hash containing the corresponding rule for
# each snapshot.
#
# @param [Nanoc::Int::ItemRep] rep The item rep for which to fetch the rules
#
# @return [Hash] The routing rules for the given rep
def routing_rules_for(rep)
rules = {}
@item_routing_rules.each do |rule|
next unless rule.applicable_to?(rep.item)
next if rule.rep_name != rep.name
next if rules.key?(rule.snapshot_name)
rules[rule.snapshot_name] = rule
end
rules
end
# Finds the filter name and arguments to use for the given layout.
#
# @param [Nanoc::Int::Layout] layout The layout for which to fetch the filter.
#
# @return [Array, nil] A tuple containing the filter name and the filter
# arguments for the given layout.
def filter_for_layout(layout)
@layout_filter_mapping.each_pair do |pattern, filter_name_and_args|
return filter_name_and_args if pattern.match?(layout.identifier)
end
nil
end
# Returns an object that can be used for uniquely identifying objects.
#
# @return [Object] An unique reference to this object
def reference
'rules'
end
def inspect
"<#{self.class}>"
end
end
end
nanoc-4.11.0/nanoc/lib/nanoc/rule_dsl/rules_loader.rb000066400000000000000000000015031340050175000224450ustar00rootroot00000000000000# frozen_string_literal: true
module Nanoc::RuleDSL
class RulesLoader
def initialize(config, rules_collection)
@dsl = Nanoc::RuleDSL::CompilerDSL.new(rules_collection, config)
end
def load
# Find rules file
rules_filenames = ['Rules', 'rules', 'Rules.rb', 'rules.rb']
rules_filename = rules_filenames.find { |f| File.file?(f) }
raise Nanoc::Int::Errors::NoRulesFileFound.new if rules_filename.nil?
parse(rules_filename)
end
def parse(rules_filename)
rules_filename = File.absolute_path(rules_filename)
# Get rule data
data = File.read(rules_filename)
old_rules_filename = @dsl.rules_filename
@dsl.rules_filename = rules_filename
@dsl.instance_eval(data, rules_filename)
@dsl.rules_filename = old_rules_filename
end
end
end
nanoc-4.11.0/nanoc/lib/nanoc/spec.rb000066400000000000000000000151241340050175000171120ustar00rootroot00000000000000# frozen_string_literal: true
module Nanoc
# @api private
module Spec
module Helper
def chdir(dir)
here = Dir.getwd
Dir.chdir(dir)
yield
ensure
Dir.chdir(here)
end
def on_windows?
Nanoc.on_windows?
end
def command?(cmd)
which, null = on_windows? ? %w[where NUL] : ['which', '/dev/null']
system("#{which} #{cmd} > #{null} 2>&1")
end
def skip_unless_have_command(cmd)
skip "Could not find external command \"#{cmd}\"" unless command?(cmd)
end
def skip_unless_gem_available(gem)
require gem
rescue LoadError
skip "Could not load gem \"#{gem}\""
end
def sleep_until(max: 3.0)
start = Time.now
loop do
diff = (Time.now - start).to_f
if diff > max
raise "Waited for #{diff}s for condition to become true, but it never did"
end
break if yield
sleep 0.1
end
end
end
class HelperContext
# @return [Nanoc::Int::DependencyTracker]
attr_reader :dependency_tracker
attr_reader :erbout
# @param [Module] mod The helper module to create a context for
def initialize(mod)
@mod = mod
@erbout = +''
@action_sequence = {}
@config = Nanoc::Int::Configuration.new(dir: Dir.getwd).with_defaults
@reps = Nanoc::Int::ItemRepRepo.new
@items = Nanoc::Int::ItemCollection.new(@config)
@layouts = Nanoc::Int::LayoutCollection.new(@config)
@dependency_tracker = Nanoc::Int::DependencyTracker.new(Object.new)
@snapshot_repo = Nanoc::Int::SnapshotRepo.new
@action_provider = new_action_provider
end
# Creates a new item and adds it to the site’s collection of items.
#
# @param [String] content The uncompiled item content
#
# @param [Hash] attributes A hash containing this item's attributes
#
# @param [Nanoc::Identifier, String] identifier This item's identifier
#
# @return [Nanoc::CompilationItemView] A view for the newly created item
def create_item(content, attributes, identifier)
item = Nanoc::Int::Item.new(content, attributes, identifier)
@items = @items.add(item)
self
end
# Creates a new layout and adds it to the site’s collection of layouts.
#
# @param [String] content The raw layout content
#
# @param [Hash] attributes A hash containing this layout's attributes
#
# @param [Nanoc::Identifier, String] identifier This layout's identifier
#
# @return [Nanoc::CompilationItemView] A view for the newly created layout
def create_layout(content, attributes, identifier)
layout = Nanoc::Int::Layout.new(content, attributes, identifier)
@layouts = @layouts.add(layout)
self
end
# Creates a new representation for the given item.
#
# @param [Nanoc::CompilationItemView] item The item to create a represetation for
#
# @param [String] path The path of the `:last` snapshot of this item representation
# @param [Symbol] rep The rep name to create
def create_rep(item, path, rep = :default)
rep = Nanoc::Int::ItemRep.new(item._unwrap, rep)
rep.paths[:last] = [path]
@reps << rep
self
end
# @return [Object] An object that includes the helper functions
def helper
mod = @mod
klass = Class.new(Nanoc::Int::Context) { include mod }
klass.new(assigns)
end
def item=(item)
@item = item ? item._unwrap : nil
end
def item_rep=(item_rep)
@item_rep = item_rep ? item_rep._unwrap : nil
end
# @return [Nanoc::MutableConfigView]
def config
assigns[:config]
end
# @return [Nanoc::CompilationItemView, nil]
def item
assigns[:item]
end
# @return [Nanoc::BasicItemRepView, nil]
def item_rep
assigns[:item_rep]
end
# @return [Nanoc::ItemCollectionWithRepsView]
def items
assigns[:items]
end
# @return [Nanoc::LayoutCollectionView]
def layouts
assigns[:layouts]
end
def action_sequence_for(obj)
@action_sequence.fetch(obj, [])
end
def update_action_sequence(obj, memory)
@action_sequence[obj] = memory
end
def snapshot_repo
view_context.snapshot_repo
end
private
def view_context
compilation_context =
Nanoc::Int::CompilationContext.new(
action_provider: @action_provider,
reps: @reps,
site: @site,
compiled_content_cache: :__compiled_content_cache,
snapshot_repo: @snapshot_repo,
)
Nanoc::ViewContextForCompilation.new(
reps: @reps,
items: @items,
dependency_tracker: @dependency_tracker,
compilation_context: compilation_context,
snapshot_repo: @snapshot_repo,
)
end
def new_action_provider
Class.new(Nanoc::Int::ActionProvider) do
def self.for(_context)
raise NotImplementedError
end
def initialize(context)
@context = context
end
def rep_names_for(_item)
[:default]
end
def action_sequence_for(obj)
@context.action_sequence_for(obj)
end
def snapshots_defs_for(_rep)
[Nanoc::Int::SnapshotDef.new(:last, binary: false)]
end
end.new(self)
end
def new_compiler_for(site)
Nanoc::Int::CompilerLoader.new.load(site, action_provider: @action_provider)
end
def site
@_site ||=
Nanoc::Int::Site.new(
config: @config,
code_snippets: [],
data_source: Nanoc::Int::InMemDataSource.new(@items, @layouts),
)
end
def assigns
{
config: Nanoc::MutableConfigView.new(@config, view_context),
item_rep: @item_rep ? Nanoc::CompilationItemRepView.new(@item_rep, view_context) : nil,
item: @item ? Nanoc::CompilationItemView.new(@item, view_context) : nil,
items: Nanoc::ItemCollectionWithRepsView.new(@items, view_context),
layouts: Nanoc::LayoutCollectionView.new(@layouts, view_context),
_erbout: @erbout,
}
end
end
module HelperHelper
def ctx
@_ctx ||= HelperContext.new(described_class)
end
def helper
@_helper ||= ctx.helper
end
end
end
end
nanoc-4.11.0/nanoc/lib/nanoc/version.rb000066400000000000000000000001441340050175000176410ustar00rootroot00000000000000# frozen_string_literal: true
module Nanoc
# The current Nanoc version.
VERSION = '4.11.0'
end
nanoc-4.11.0/nanoc/nanoc.gemspec000066400000000000000000000026511340050175000164330ustar00rootroot00000000000000# frozen_string_literal: true
require_relative 'lib/nanoc/version'
Gem::Specification.new do |s|
s.name = 'nanoc'
s.version = Nanoc::VERSION
s.homepage = 'http://nanoc.ws/'
s.summary = 'A static-site generator with a focus on flexibility.'
s.description = 'Nanoc is a static-site generator focused on flexibility. It transforms content from a format such as Markdown or AsciiDoc into another format, usually HTML, and lays out pages consistently to retain the site’s look and feel throughout. Static sites built with Nanoc can be deployed to any web server.'
s.author = 'Denis Defreyne'
s.email = 'denis+rubygems@denis.ws'
s.license = 'MIT'
s.files = Dir['*.md'] + ['LICENSE'] + Dir['bin/*'] + Dir['lib/**/*.rb'] + Dir['lib/**/*-schema.json']
s.executables = ['nanoc']
s.require_paths = ['lib']
s.required_ruby_version = '~> 2.4'
s.add_runtime_dependency('addressable', '~> 2.5')
s.add_runtime_dependency('cri', '~> 2.15')
s.add_runtime_dependency('ddmemoize', '~> 1.0')
s.add_runtime_dependency('ddmetrics', '~> 1.0')
s.add_runtime_dependency('ddplugin', '~> 1.0')
s.add_runtime_dependency('hamster', '~> 3.0')
s.add_runtime_dependency('json_schema', '~> 0.19')
s.add_runtime_dependency('parallel', '~> 1.12')
s.add_runtime_dependency('ref', '~> 2.0')
s.add_runtime_dependency('slow_enumerator_tools', '~> 1.0')
s.add_runtime_dependency('tomlrb', '~> 1.2')
end
nanoc-4.11.0/nanoc/nanoc.manifest000066400000000000000000000240461340050175000166200ustar00rootroot00000000000000LICENSE
NEWS.md
README.md
bin/nanoc
lib/nanoc.rb
lib/nanoc/base.rb
lib/nanoc/base/assertions.rb
lib/nanoc/base/changes_stream.rb
lib/nanoc/base/contracts_support.rb
lib/nanoc/base/core_ext.rb
lib/nanoc/base/core_ext/array.rb
lib/nanoc/base/core_ext/hash.rb
lib/nanoc/base/core_ext/string.rb
lib/nanoc/base/entities.rb
lib/nanoc/base/entities/action_sequence.rb
lib/nanoc/base/entities/checksum_collection.rb
lib/nanoc/base/entities/code_snippet.rb
lib/nanoc/base/entities/configuration.rb
lib/nanoc/base/entities/configuration-schema.json
lib/nanoc/base/entities/content.rb
lib/nanoc/base/entities/context.rb
lib/nanoc/base/entities/dependency.rb
lib/nanoc/base/entities/directed_graph.rb
lib/nanoc/base/entities/document.rb
lib/nanoc/base/entities/identifiable_collection.rb
lib/nanoc/base/entities/identifier.rb
lib/nanoc/base/entities/item_collection.rb
lib/nanoc/base/entities/item_rep.rb
lib/nanoc/base/entities/item.rb
lib/nanoc/base/entities/layout_collection.rb
lib/nanoc/base/entities/layout.rb
lib/nanoc/base/entities/lazy_value.rb
lib/nanoc/base/entities/outdatedness_reasons.rb
lib/nanoc/base/entities/outdatedness_status.rb
lib/nanoc/base/entities/pattern.rb
lib/nanoc/base/entities/processing_action.rb
lib/nanoc/base/entities/processing_actions.rb
lib/nanoc/base/entities/processing_actions/filter.rb
lib/nanoc/base/entities/processing_actions/layout.rb
lib/nanoc/base/entities/processing_actions/snapshot.rb
lib/nanoc/base/entities/props.rb
lib/nanoc/base/entities/site.rb
lib/nanoc/base/entities/snapshot_def.rb
lib/nanoc/base/error.rb
lib/nanoc/base/errors.rb
lib/nanoc/base/feature.rb
lib/nanoc/base/repos.rb
lib/nanoc/base/repos/action_sequence_store.rb
lib/nanoc/base/repos/aggregate_data_source.rb
lib/nanoc/base/repos/checksum_store.rb
lib/nanoc/base/repos/compiled_content_cache.rb
lib/nanoc/base/repos/config_loader.rb
lib/nanoc/base/repos/data_source.rb
lib/nanoc/base/repos/dependency_store.rb
lib/nanoc/base/repos/in_mem_data_source.rb
lib/nanoc/base/repos/item_rep_repo.rb
lib/nanoc/base/repos/outdatedness_store.rb
lib/nanoc/base/repos/prefixed_data_source.rb
lib/nanoc/base/repos/site_loader.rb
lib/nanoc/base/repos/snapshot_repo.rb
lib/nanoc/base/repos/store.rb
lib/nanoc/base/services.rb
lib/nanoc/base/services/action_provider.rb
lib/nanoc/base/services/action_sequence_builder.rb
lib/nanoc/base/services/checksummer.rb
lib/nanoc/base/services/compilation_context.rb
lib/nanoc/base/services/compiler_loader.rb
lib/nanoc/base/services/compiler.rb
lib/nanoc/base/services/compiler/phases.rb
lib/nanoc/base/services/compiler/phases/abstract.rb
lib/nanoc/base/services/compiler/phases/cache.rb
lib/nanoc/base/services/compiler/phases/mark_done.rb
lib/nanoc/base/services/compiler/phases/recalculate.rb
lib/nanoc/base/services/compiler/phases/resume.rb
lib/nanoc/base/services/compiler/phases/write.rb
lib/nanoc/base/services/compiler/stage.rb
lib/nanoc/base/services/compiler/stages.rb
lib/nanoc/base/services/compiler/stages/build_reps.rb
lib/nanoc/base/services/compiler/stages/calculate_checksums.rb
lib/nanoc/base/services/compiler/stages/cleanup.rb
lib/nanoc/base/services/compiler/stages/compile_reps.rb
lib/nanoc/base/services/compiler/stages/determine_outdatedness.rb
lib/nanoc/base/services/compiler/stages/forget_outdated_dependencies.rb
lib/nanoc/base/services/compiler/stages/load_stores.rb
lib/nanoc/base/services/compiler/stages/postprocess.rb
lib/nanoc/base/services/compiler/stages/preprocess.rb
lib/nanoc/base/services/compiler/stages/prune.rb
lib/nanoc/base/services/compiler/stages/store_post_compilation_state.rb
lib/nanoc/base/services/compiler/stages/store_pre_compilation_state.rb
lib/nanoc/base/services/dependency_tracker.rb
lib/nanoc/base/services/executor.rb
lib/nanoc/base/services/filter.rb
lib/nanoc/base/services/instrumentor.rb
lib/nanoc/base/services/item_rep_builder.rb
lib/nanoc/base/services/item_rep_router.rb
lib/nanoc/base/services/item_rep_selector.rb
lib/nanoc/base/services/item_rep_writer.rb
lib/nanoc/base/services/notification_center.rb
lib/nanoc/base/services/outdatedness_checker.rb
lib/nanoc/base/services/outdatedness_rule.rb
lib/nanoc/base/services/outdatedness_rules.rb
lib/nanoc/base/services/outdatedness_rules/attributes_modified.rb
lib/nanoc/base/services/outdatedness_rules/code_snippets_modified.rb
lib/nanoc/base/services/outdatedness_rules/content_modified.rb
lib/nanoc/base/services/outdatedness_rules/item_collection_extended.rb
lib/nanoc/base/services/outdatedness_rules/layout_collection_extended.rb
lib/nanoc/base/services/outdatedness_rules/not_written.rb
lib/nanoc/base/services/outdatedness_rules/rules_modified.rb
lib/nanoc/base/services/outdatedness_rules/uses_always_outdated_filter.rb
lib/nanoc/base/services/pruner.rb
lib/nanoc/base/services/temp_filename_factory.rb
lib/nanoc/base/views.rb
lib/nanoc/base/views/basic_item_rep_collection_view.rb
lib/nanoc/base/views/basic_item_rep_view.rb
lib/nanoc/base/views/basic_item_view.rb
lib/nanoc/base/views/compilation_item_rep_collection_view.rb
lib/nanoc/base/views/compilation_item_rep_view.rb
lib/nanoc/base/views/compilation_item_view.rb
lib/nanoc/base/views/config_view.rb
lib/nanoc/base/views/identifiable_collection_view.rb
lib/nanoc/base/views/item_collection_with_reps_view.rb
lib/nanoc/base/views/item_collection_without_reps_view.rb
lib/nanoc/base/views/layout_collection_view.rb
lib/nanoc/base/views/layout_view.rb
lib/nanoc/base/views/mixins/document_view_mixin.rb
lib/nanoc/base/views/mixins/mutable_document_view_mixin.rb
lib/nanoc/base/views/mutable_config_view.rb
lib/nanoc/base/views/mutable_identifiable_collection_view.rb
lib/nanoc/base/views/mutable_item_collection_view.rb
lib/nanoc/base/views/mutable_item_view.rb
lib/nanoc/base/views/mutable_layout_collection_view.rb
lib/nanoc/base/views/mutable_layout_view.rb
lib/nanoc/base/views/post_compile_item_collection_view.rb
lib/nanoc/base/views/post_compile_item_rep_collection_view.rb
lib/nanoc/base/views/post_compile_item_rep_view.rb
lib/nanoc/base/views/post_compile_item_view.rb
lib/nanoc/base/views/view_context_for_compilation.rb
lib/nanoc/base/views/view_context_for_pre_compilation.rb
lib/nanoc/base/views/view_context_for_shell.rb
lib/nanoc/base/views/view.rb
lib/nanoc/checking.rb
lib/nanoc/checking/check.rb
lib/nanoc/checking/checks.rb
lib/nanoc/checking/checks/css.rb
lib/nanoc/checking/checks/external_links.rb
lib/nanoc/checking/checks/html.rb
lib/nanoc/checking/checks/internal_links.rb
lib/nanoc/checking/checks/mixed_content.rb
lib/nanoc/checking/checks/stale.rb
lib/nanoc/checking/checks/w3c_validator.rb
lib/nanoc/checking/dsl.rb
lib/nanoc/checking/issue.rb
lib/nanoc/checking/loader.rb
lib/nanoc/checking/runner.rb
lib/nanoc/cli.rb
lib/nanoc/cli/ansi_string_colorizer.rb
lib/nanoc/cli/cleaning_stream.rb
lib/nanoc/cli/command_runner.rb
lib/nanoc/cli/commands/check.rb
lib/nanoc/cli/commands/compile_listeners/abstract.rb
lib/nanoc/cli/commands/compile_listeners/aggregate.rb
lib/nanoc/cli/commands/compile_listeners/debug_printer.rb
lib/nanoc/cli/commands/compile_listeners/diff_generator.rb
lib/nanoc/cli/commands/compile_listeners/file_action_printer.rb
lib/nanoc/cli/commands/compile_listeners/timing_recorder.rb
lib/nanoc/cli/commands/compile.rb
lib/nanoc/cli/commands/create-site.rb
lib/nanoc/cli/commands/deploy.rb
lib/nanoc/cli/commands/nanoc.rb
lib/nanoc/cli/commands/prune.rb
lib/nanoc/cli/commands/shell.rb
lib/nanoc/cli/commands/show-data.rb
lib/nanoc/cli/commands/show-plugins.rb
lib/nanoc/cli/commands/show-rules.rb
lib/nanoc/cli/commands/view.rb
lib/nanoc/cli/error_handler.rb
lib/nanoc/cli/logger.rb
lib/nanoc/cli/stack_trace_writer.rb
lib/nanoc/cli/stream_cleaners.rb
lib/nanoc/cli/stream_cleaners/abstract.rb
lib/nanoc/cli/stream_cleaners/ansi_colors.rb
lib/nanoc/cli/stream_cleaners/utf8.rb
lib/nanoc/cli/transform.rb
lib/nanoc/data_sources.rb
lib/nanoc/data_sources/filesystem.rb
lib/nanoc/data_sources/filesystem/errors.rb
lib/nanoc/data_sources/filesystem/tools.rb
lib/nanoc/data_sources/filesystem/parser.rb
lib/nanoc/deploying.rb
lib/nanoc/deploying/deployer.rb
lib/nanoc/deploying/deployers.rb
lib/nanoc/deploying/deployers/fog.rb
lib/nanoc/deploying/deployers/git.rb
lib/nanoc/deploying/deployers/rsync.rb
lib/nanoc/extra.rb
lib/nanoc/extra/core_ext.rb
lib/nanoc/extra/core_ext/pathname.rb
lib/nanoc/extra/core_ext/time.rb
lib/nanoc/extra/jruby_nokogiri_warner.rb
lib/nanoc/extra/link_collector.rb
lib/nanoc/extra/piper.rb
lib/nanoc/filters.rb
lib/nanoc/filters/asciidoc.rb
lib/nanoc/filters/asciidoctor.rb
lib/nanoc/filters/bluecloth.rb
lib/nanoc/filters/coffeescript.rb
lib/nanoc/filters/colorize_syntax.rb
lib/nanoc/filters/colorize_syntax/colorizers.rb
lib/nanoc/filters/erb.rb
lib/nanoc/filters/erubi.rb
lib/nanoc/filters/erubis.rb
lib/nanoc/filters/haml.rb
lib/nanoc/filters/handlebars.rb
lib/nanoc/filters/kramdown.rb
lib/nanoc/filters/less.rb
lib/nanoc/filters/markaby.rb
lib/nanoc/filters/maruku.rb
lib/nanoc/filters/mustache.rb
lib/nanoc/filters/pandoc.rb
lib/nanoc/filters/rainpress.rb
lib/nanoc/filters/rdiscount.rb
lib/nanoc/filters/rdoc.rb
lib/nanoc/filters/redcarpet.rb
lib/nanoc/filters/redcloth.rb
lib/nanoc/filters/relativize_paths.rb
lib/nanoc/filters/rubypants.rb
lib/nanoc/filters/sass.rb
lib/nanoc/filters/sass/functions.rb
lib/nanoc/filters/sass/importer.rb
lib/nanoc/filters/slim.rb
lib/nanoc/filters/typogruby.rb
lib/nanoc/filters/uglify_js.rb
lib/nanoc/filters/xsl.rb
lib/nanoc/filters/yui_compressor.rb
lib/nanoc/helpers.rb
lib/nanoc/helpers/blogging.rb
lib/nanoc/helpers/breadcrumbs.rb
lib/nanoc/helpers/capturing.rb
lib/nanoc/helpers/child_parent.rb
lib/nanoc/helpers/filtering.rb
lib/nanoc/helpers/html_escape.rb
lib/nanoc/helpers/link_to.rb
lib/nanoc/helpers/rendering.rb
lib/nanoc/helpers/tagging.rb
lib/nanoc/helpers/text.rb
lib/nanoc/helpers/xml_sitemap.rb
lib/nanoc/rule_dsl.rb
lib/nanoc/rule_dsl/action_provider.rb
lib/nanoc/rule_dsl/action_recorder.rb
lib/nanoc/rule_dsl/action_sequence_calculator.rb
lib/nanoc/rule_dsl/compiler_dsl.rb
lib/nanoc/rule_dsl/compilation_rule_context.rb
lib/nanoc/rule_dsl/compilation_rule.rb
lib/nanoc/rule_dsl/routing_rule_context.rb
lib/nanoc/rule_dsl/routing_rule.rb
lib/nanoc/rule_dsl/rule.rb
lib/nanoc/rule_dsl/rule_context.rb
lib/nanoc/rule_dsl/rules_collection.rb
lib/nanoc/rule_dsl/rules_loader.rb
lib/nanoc/spec.rb
lib/nanoc/version.rb
nanoc-4.11.0/nanoc/spec/000077500000000000000000000000001340050175000147165ustar00rootroot00000000000000nanoc-4.11.0/nanoc/spec/contributors_spec.rb000066400000000000000000000012241340050175000210110ustar00rootroot00000000000000# frozen_string_literal: true
describe 'list of contributors in README', chdir: false do
let(:contributors_in_readme) do
File.readlines('../README.md').last.chomp("\n").split(', ')
end
let(:contributors_in_release_notes) do
File.read('NEWS.md').scan(/\[[^\]]+\]$/).map { |s| s[1..-2].split(', ') }.flatten
end
it 'should include everyone mentioned in NEWS.md' do
diff = (contributors_in_release_notes - contributors_in_readme).uniq.sort
expect(diff).to be_empty, "some contributors are missing from the README: #{diff.join(', ')}"
end
it 'should be sorted' do
expect(contributors_in_readme).to be_humanly_sorted
end
end
nanoc-4.11.0/nanoc/spec/gem_spec.rb000066400000000000000000000007601340050175000170300ustar00rootroot00000000000000# frozen_string_literal: true
describe 'nanoc.gem', chdir: false, stdio: true do
around do |ex|
Dir['*.gem'].each { |f| FileUtils.rm(f) }
ex.run
Dir['*.gem'].each { |f| FileUtils.rm(f) }
end
subject do
piper = Nanoc::Extra::Piper.new(stdout: $stdout, stderr: $stderr)
piper.run(%w[gem build nanoc.gemspec], nil)
end
it 'builds gem' do
expect { subject }
.to change { Dir['*.gem'] }
.from([])
.to(include(match(/^nanoc-.*\.gem$/)))
end
end
nanoc-4.11.0/nanoc/spec/manifest_spec.rb000066400000000000000000000002101340050175000200540ustar00rootroot00000000000000# frozen_string_literal: true
describe 'manifest', chdir: false do
example do
expect('nanoc').to have_a_valid_manifest
end
end
nanoc-4.11.0/nanoc/spec/nanoc/000077500000000000000000000000001340050175000160145ustar00rootroot00000000000000nanoc-4.11.0/nanoc/spec/nanoc/base/000077500000000000000000000000001340050175000167265ustar00rootroot00000000000000nanoc-4.11.0/nanoc/spec/nanoc/base/changes_stream_spec.rb000066400000000000000000000022741340050175000232550ustar00rootroot00000000000000# frozen_string_literal: true
describe Nanoc::ChangesStream do
let(:simple_stream) do
described_class.new do |cl|
cl.unknown
sleep
end
end
it 'returns a stream of events generated by the listener' do
buffered_stream = SlowEnumeratorTools.buffer(simple_stream, 1)
expect(buffered_stream.take(1).to_a).to eq([:unknown])
end
describe '#map' do
it 'returns a new maped enum' do
stream = simple_stream.map { |e| e.to_s.upcase }
buffered_stream = SlowEnumeratorTools.buffer(stream, 1)
expect(buffered_stream.take(1).to_a).to eq(['UNKNOWN'])
end
end
describe '#to_enum' do
it 'returns an enumerator corresponding to itself' do
buffered_stream = SlowEnumeratorTools.buffer(simple_stream.to_enum, 1)
expect(buffered_stream.take(1).to_a).to eq([:unknown])
end
end
describe '#stop' do
let(:simple_stream) do
described_class.new do |cl|
cl.to_stop { $changes_stream_stopped = true }
sleep
end
end
example do
SlowEnumeratorTools.buffer(simple_stream, 1)
sleep 0.1
expect { simple_stream.stop }.to change { $changes_stream_stopped }.from(nil).to(true)
end
end
end
nanoc-4.11.0/nanoc/spec/nanoc/base/checksummer_spec.rb000066400000000000000000000353531340050175000226040ustar00rootroot00000000000000# frozen_string_literal: true
describe Nanoc::Int::Checksummer::VerboseDigest do
let(:digest) { described_class.new }
it 'concatenates' do
digest.update('foo')
digest.update('bar')
expect(digest.to_s).to eql('foobar')
end
end
describe Nanoc::Int::Checksummer::CompactDigest do
let(:digest) { described_class.new }
it 'uses SHA1 and Base64' do
digest.update('foo')
digest.update('bar')
expect(digest.to_s).to eql(Digest::SHA1.base64digest('foobar'))
end
end
describe Nanoc::Int::Checksummer do
subject { described_class.calc(obj, Nanoc::Int::Checksummer::VerboseDigest) }
describe '.calc_for_each_attribute_of' do
let(:obj) { Nanoc::Int::Item.new('asdf', { 'foo' => 'bar' }, '/foo.md') }
context 'compact' do
subject do
described_class.calc_for_each_attribute_of(obj)
end
it { is_expected.to have_key(:foo) }
end
context 'verbose' do
subject do
described_class.calc_for_each_attribute_of(obj, Nanoc::Int::Checksummer::VerboseDigest)
end
it { is_expected.to eq(foo: 'String') }
end
end
context 'String' do
let(:obj) { 'hello' }
it { is_expected.to eql('String') }
end
context 'Symbol' do
let(:obj) { :hello }
it { is_expected.to eql('Symbol') }
end
context 'nil' do
let(:obj) { nil }
it { is_expected.to eql('NilClass<>') }
end
context 'true' do
let(:obj) { true }
it { is_expected.to eql('TrueClass<>') }
end
context 'false' do
let(:obj) { false }
it { is_expected.to eql('FalseClass<>') }
end
context 'Array' do
let(:obj) { %w[hello goodbye] }
it { is_expected.to eql('Array,String,>') }
context 'different order' do
let(:obj) { %w[goodbye hello] }
it { is_expected.to eql('Array,String,>') }
end
context 'recursive' do
let(:obj) { [].tap { |arr| arr << ['hello', arr] } }
it { is_expected.to eql('Array,Array,>,>') }
end
context 'non-serializable' do
let(:obj) { [-> {}] }
it { is_expected.to match(/\AArray>,>\z/) }
end
end
context 'Hash' do
let(:obj) { { 'a' => 'foo', 'b' => 'bar' } }
it { is_expected.to eql('Hash=String,String=String,>') }
context 'different order' do
let(:obj) { { 'b' => 'bar', 'a' => 'foo' } }
it { is_expected.to eql('Hash=String,String=String,>') }
end
context 'non-serializable' do
let(:obj) { { 'a' => -> {} } }
it { is_expected.to match(/\AHash=Proc<#>,>\z/) }
end
context 'recursive values' do
let(:obj) { {}.tap { |hash| hash['a'] = hash } }
it { is_expected.to eql('Hash=Hash,>') }
end
context 'recursive keys' do
let(:obj) { {}.tap { |hash| hash[hash] = 'hello' } }
it { is_expected.to eql('Hash=String,>') }
end
end
context 'Pathname' do
let(:obj) { ::Pathname.new(filename) }
let(:filename) { '/tmp/whatever' }
let(:mtime) { 200 }
let(:data) { 'stuffs' }
before do
FileUtils.mkdir_p(File.dirname(filename))
File.write(filename, data)
File.utime(mtime, mtime, filename)
end
it { is_expected.to eql('Pathname<6-200>') }
context 'does not exist' do
before do
FileUtils.rm_rf(filename)
end
it { is_expected.to eql('Pathname') }
end
context 'different data' do
let(:data) { 'other stuffs :o' }
it { is_expected.to eql('Pathname<15-200>') }
end
end
context 'Time' do
let(:obj) { Time.at(111_223) }
it { is_expected.to eql('Time<111223>') }
end
context 'Float' do
let(:obj) { 3.14 }
it { is_expected.to eql('Float<3.14>') }
end
context 'Fixnum/Integer' do
let(:obj) { 3 }
it { is_expected.to match(/\A(Integer|Fixnum)<3>\z/) }
end
context 'Nanoc::Identifier' do
let(:obj) { Nanoc::Identifier.new('/foo.md') }
it { is_expected.to eql('Nanoc::Identifier>') }
end
context 'Nanoc::RuleDSL::RulesCollection' do
let(:obj) do
Nanoc::RuleDSL::RulesCollection.new.tap { |rc| rc.data = data }
end
let(:data) { 'STUFF!' }
it { is_expected.to eql('Nanoc::RuleDSL::RulesCollection>') }
end
context 'Nanoc::Int::CodeSnippet' do
let(:obj) { Nanoc::Int::CodeSnippet.new('asdf', '/bob.rb') }
it { is_expected.to eql('Nanoc::Int::CodeSnippet>') }
end
context 'Nanoc::Int::Configuration' do
let(:obj) { Nanoc::Int::Configuration.new(dir: Dir.getwd, hash: { 'foo' => 'bar' }) }
it { is_expected.to eql('Nanoc::Int::Configuration=String,>') }
end
context 'Nanoc::Int::Item' do
let(:obj) { Nanoc::Int::Item.new('asdf', { 'foo' => 'bar' }, '/foo.md') }
it { is_expected.to eql('Nanoc::Int::Item>,attributes=Hash=String,>,identifier=Nanoc::Identifier>>') }
context 'binary' do
let(:filename) { File.expand_path('foo.dat') }
let(:content) { Nanoc::Int::BinaryContent.new(filename) }
let(:obj) { Nanoc::Int::Item.new(content, { 'foo' => 'bar' }, '/foo.md') }
let(:mtime) { 200 }
let(:data) { 'stuffs' }
before do
File.write(content.filename, data)
File.utime(mtime, mtime, content.filename)
end
it { is_expected.to eql('Nanoc::Int::Item>,attributes=Hash=String,>,identifier=Nanoc::Identifier>>') }
end
context 'recursive attributes' do
before do
obj.attributes[:foo] = obj
end
it { is_expected.to eql('Nanoc::Int::Item>,attributes=Hash=Nanoc::Int::Item,>,identifier=Nanoc::Identifier>>') }
end
context 'with checksum' do
let(:obj) { Nanoc::Int::Item.new('asdf', { 'foo' => 'bar' }, '/foo.md', checksum_data: 'abcdef') }
it { is_expected.to eql('Nanoc::Int::Item') }
end
context 'with content checksum' do
let(:obj) { Nanoc::Int::Item.new('asdf', { 'foo' => 'bar' }, '/foo.md', content_checksum_data: 'con-cs') }
it { is_expected.to eql('Nanoc::Int::Item=String,>,identifier=Nanoc::Identifier>>') }
end
context 'with attributes checksum' do
let(:obj) { Nanoc::Int::Item.new('asdf', { 'foo' => 'bar' }, '/foo.md', attributes_checksum_data: 'attr-cs') }
it { is_expected.to eql('Nanoc::Int::Item>,attributes_checksum_data=attr-cs,identifier=Nanoc::Identifier>>') }
end
end
context 'Nanoc::Int::Layout' do
let(:obj) { Nanoc::Int::Layout.new('asdf', { 'foo' => 'bar' }, '/foo.md') }
it { is_expected.to eql('Nanoc::Int::Layout>,attributes=Hash=String,>,identifier=Nanoc::Identifier>>') }
context 'recursive attributes' do
before do
obj.attributes[:foo] = obj
end
it { is_expected.to eql('Nanoc::Int::Layout>,attributes=Hash=Nanoc::Int::Layout,>,identifier=Nanoc::Identifier>>') }
end
context 'with checksum' do
let(:obj) { Nanoc::Int::Layout.new('asdf', { 'foo' => 'bar' }, '/foo.md', checksum_data: 'abcdef') }
it { is_expected.to eql('Nanoc::Int::Layout') }
end
end
context 'Nanoc::CompilationItemView' do
let(:obj) { Nanoc::CompilationItemView.new(item, nil) }
let(:item) { Nanoc::Int::Item.new('asdf', {}, '/foo.md') }
it { is_expected.to eql('Nanoc::CompilationItemView>,attributes=Hash<>,identifier=Nanoc::Identifier>>>') }
end
context 'Nanoc::Int::ItemRep' do
let(:obj) { Nanoc::Int::ItemRep.new(item, :pdf) }
let(:item) { Nanoc::Int::Item.new('asdf', {}, '/foo.md') }
it { is_expected.to eql('Nanoc::Int::ItemRep- >,attributes=Hash<>,identifier=Nanoc::Identifier
>>,name=Symbol>') }
end
context 'Nanoc::BasicItemRepView' do
let(:obj) { Nanoc::BasicItemRepView.new(rep, :_unused_context) }
let(:rep) { Nanoc::Int::ItemRep.new(item, :pdf) }
let(:item) { Nanoc::Int::Item.new('asdf', {}, '/foo.md') }
it { is_expected.to eql('Nanoc::BasicItemRepView>,attributes=Hash<>,identifier=Nanoc::Identifier>>,name=Symbol>>') }
end
context 'Nanoc::CompilationItemRepView' do
let(:obj) { Nanoc::CompilationItemRepView.new(rep, :_unused_context) }
let(:rep) { Nanoc::Int::ItemRep.new(item, :pdf) }
let(:item) { Nanoc::Int::Item.new('asdf', {}, '/foo.md') }
it { is_expected.to eql('Nanoc::CompilationItemRepView>,attributes=Hash<>,identifier=Nanoc::Identifier>>,name=Symbol>>') }
end
context 'Nanoc::BasicItemView' do
let(:obj) { Nanoc::BasicItemView.new(item, nil) }
let(:item) { Nanoc::Int::Item.new('asdf', {}, '/foo.md') }
it { is_expected.to eql('Nanoc::BasicItemView>,attributes=Hash<>,identifier=Nanoc::Identifier>>>') }
end
context 'Nanoc::LayoutView' do
let(:obj) { Nanoc::LayoutView.new(layout, nil) }
let(:layout) { Nanoc::Int::Layout.new('asdf', {}, '/foo.md') }
it { is_expected.to eql('Nanoc::LayoutView>,attributes=Hash<>,identifier=Nanoc::Identifier>>>') }
end
context 'Nanoc::ConfigView' do
let(:obj) { Nanoc::ConfigView.new(config, nil) }
let(:config) { Nanoc::Int::Configuration.new(dir: Dir.getwd, hash: { 'foo' => 'bar' }) }
it { is_expected.to eql('Nanoc::ConfigView=String,>>') }
end
context 'Nanoc::ItemCollectionWithRepsView' do
let(:obj) { Nanoc::ItemCollectionWithRepsView.new(wrapped, nil) }
let(:config) { Nanoc::Int::Configuration.new(dir: Dir.getwd, hash: { 'foo' => 'bar' }) }
let(:wrapped) do
Nanoc::Int::ItemCollection.new(
config,
[
Nanoc::Int::Item.new('foo', {}, '/foo.md'),
Nanoc::Int::Item.new('bar', {}, '/foo.md'),
],
)
end
it { is_expected.to eql('Nanoc::ItemCollectionWithRepsView>,attributes=Hash<>,identifier=Nanoc::Identifier>>,Nanoc::Int::Item>,attributes=Hash<>,identifier=Nanoc::Identifier>>,>>') }
end
context 'Nanoc::ItemCollectionWithoutRepsView' do
let(:obj) { Nanoc::ItemCollectionWithoutRepsView.new(wrapped, nil) }
let(:config) { Nanoc::Int::Configuration.new(dir: Dir.getwd, hash: { 'foo' => 'bar' }) }
let(:wrapped) do
Nanoc::Int::ItemCollection.new(
config,
[
Nanoc::Int::Item.new('foo', {}, '/foo.md'),
Nanoc::Int::Item.new('bar', {}, '/foo.md'),
],
)
end
it { is_expected.to eql('Nanoc::ItemCollectionWithoutRepsView>,attributes=Hash<>,identifier=Nanoc::Identifier>>,Nanoc::Int::Item>,attributes=Hash<>,identifier=Nanoc::Identifier>>,>>') }
end
context 'Nanoc::RuleDSL::CompilationRuleContext' do
let(:obj) { Nanoc::RuleDSL::CompilationRuleContext.new(rep: rep, site: site, recorder: recorder, view_context: view_context) }
let(:rep) { Nanoc::Int::ItemRep.new(item, :pdf) }
let(:item) { Nanoc::Int::Item.new('stuff', {}, '/stuff.md') }
let(:site) do
Nanoc::Int::Site.new(
config: config,
code_snippets: code_snippets,
data_source: Nanoc::Int::InMemDataSource.new(items, layouts),
)
end
let(:config) { Nanoc::Int::Configuration.new(dir: Dir.getwd, hash: { 'foo' => 'bar' }) }
let(:code_snippets) { [Nanoc::Int::CodeSnippet.new('asdf', '/bob.rb')] }
let(:items) { Nanoc::Int::ItemCollection.new(config, [item]) }
let(:layouts) { [Nanoc::Int::Layout.new('asdf', {}, '/foo.md')] }
let(:recorder) { Nanoc::RuleDSL::ActionRecorder.new(rep) }
let(:view_context) { Nanoc::ViewContextForPreCompilation.new(items: items) }
let(:expected_item_checksum) { 'Nanoc::Int::Item>,attributes=Hash<>,identifier=Nanoc::Identifier>>' }
let(:expected_item_rep_checksum) { 'Nanoc::Int::ItemRep- >' }
let(:expected_layout_checksum) { 'Nanoc::Int::Layout
>,attributes=Hash<>,identifier=Nanoc::Identifier>>' }
let(:expected_config_checksum) { 'Nanoc::Int::Configuration=String,>' }
let(:expected_checksum) do
[
'Nanoc::RuleDSL::CompilationRuleContext<',
'item=',
'Nanoc::BasicItemView<' + expected_item_checksum + '>',
',rep=',
'Nanoc::BasicItemRepView<' + expected_item_rep_checksum + '>',
',items=',
'Nanoc::ItemCollectionWithoutRepsView>',
',layouts=',
'Nanoc::LayoutCollectionView>',
',config=',
'Nanoc::ConfigView<' + expected_config_checksum + '>',
'>',
].join('')
end
it { is_expected.to eql(expected_checksum) }
end
context 'Nanoc::Int::Context' do
let(:obj) { Nanoc::Int::Context.new(foo: 123) }
it { is_expected.to match(/\ANanoc::Int::Context<@foo=(Fixnum|Integer)<123>,>\z/) }
end
context 'Sass::Importers::Filesystem' do
let(:obj) { Sass::Importers::Filesystem.new('/foo') }
before { require 'sass' }
it { is_expected.to match(%r{\ASass::Importers::Filesystem\z}) }
end
context 'other marshal-able classes' do
let(:obj) { klass.new('hello') }
let(:klass) do
Class.new do
def initialize(arg)
@arg = arg
end
end
end
it { is_expected.to match(/\A#<.*>\z/) }
end
context 'other non-marshal-able classes' do
let(:obj) { proc {} }
it { is_expected.to match(/\AProc<#>\z/) }
end
end
nanoc-4.11.0/nanoc/spec/nanoc/base/compiler_spec.rb000066400000000000000000000132521340050175000221020ustar00rootroot00000000000000# frozen_string_literal: true
describe Nanoc::Int::Compiler do
let(:compiler) do
described_class.new(
site,
compiled_content_cache: compiled_content_cache,
checksum_store: checksum_store,
action_sequence_store: action_sequence_store,
action_provider: action_provider,
dependency_store: dependency_store,
outdatedness_store: outdatedness_store,
)
end
let(:checksum_store) { Nanoc::Int::ChecksumStore.new(config: config, objects: items) }
let(:action_sequence_store) { Nanoc::Int::ActionSequenceStore.new(config: config) }
let(:dependency_store) { Nanoc::Int::DependencyStore.new(items, layouts, config) }
let(:outdatedness_store) { Nanoc::Int::OutdatednessStore.new(config: config) }
let(:action_provider) { double(:action_provider) }
let(:compiled_content_cache) do
Nanoc::Int::CompiledContentCache.new(config: config)
end
let(:rep) { Nanoc::Int::ItemRep.new(item, :default) }
let(:item) { Nanoc::Int::Item.new('<%= 1 + 2 %>', {}, '/hi.md') }
let(:other_rep) { Nanoc::Int::ItemRep.new(other_item, :default) }
let(:other_item) { Nanoc::Int::Item.new('other content', {}, '/other.md') }
let(:site) do
Nanoc::Int::Site.new(
config: config,
code_snippets: code_snippets,
data_source: Nanoc::Int::InMemDataSource.new(items, layouts),
)
end
let(:config) { Nanoc::Int::Configuration.new(dir: Dir.getwd).with_defaults }
let(:code_snippets) { [] }
let(:items) do
Nanoc::Int::ItemCollection.new(config, [item, other_item])
end
let(:layouts) do
Nanoc::Int::LayoutCollection.new(config)
end
let(:memory) do
actions =
[
Nanoc::Int::ProcessingActions::Filter.new(:erb, {}),
Nanoc::Int::ProcessingActions::Snapshot.new([:last], []),
]
Nanoc::Int::ActionSequence.new(nil, actions: actions)
end
let(:action_sequences) do
{ rep => memory, other_rep => memory }
end
before do
allow(Nanoc::Int::NotificationCenter).to receive(:post)
end
describe '#compile_rep' do
let(:stage) { compiler.send(:compile_reps_stage, action_sequences, reps) }
subject { stage.send(:compile_rep, rep, phase_stack: phase_stack, is_outdated: is_outdated) }
let(:is_outdated) { true }
let(:phase_stack) { stage.send(:build_phase_stack) }
let(:reps) do
Nanoc::Int::ItemRepRepo.new.tap do |rs|
rs << rep
rs << other_rep
rs.each do |rep|
rep.snapshot_defs << Nanoc::Int::SnapshotDef.new(:last, binary: false)
end
end
end
it 'generates expected output' do
reps = Nanoc::Int::ItemRepRepo.new
expect { subject }
.to change { compiler.compilation_context(reps: reps).snapshot_repo.get(rep, :last) }
.from(nil)
.to(some_textual_content('3'))
end
it 'generates notifications in the proper order' do
expect(Nanoc::Int::NotificationCenter).to receive(:post).with(:compilation_started, rep).ordered
expect(Nanoc::Int::NotificationCenter).to receive(:post).with(:filtering_started, rep, :erb).ordered
expect(Nanoc::Int::NotificationCenter).to receive(:post).with(:filtering_ended, rep, :erb).ordered
expect(Nanoc::Int::NotificationCenter).to receive(:post).with(:compilation_ended, rep).ordered
subject
end
context 'interrupted compilation' do
let(:item) { Nanoc::Int::Item.new('other=<%= @items["/other.*"].compiled_content %>', {}, '/hi.md') }
it 'generates expected output' do
reps = Nanoc::Int::ItemRepRepo.new
expect(compiler.compilation_context(reps: reps).snapshot_repo.get(rep, :last)).to be_nil
expect { stage.send(:compile_rep, rep, phase_stack: phase_stack, is_outdated: true) }
.to raise_error(Nanoc::Int::Errors::UnmetDependency)
stage.send(:compile_rep, other_rep, phase_stack: phase_stack, is_outdated: true)
stage.send(:compile_rep, rep, phase_stack: phase_stack, is_outdated: true)
expect(compiler.compilation_context(reps: reps).snapshot_repo.get(rep, :last).string).to eql('other=other content')
end
it 'generates notifications in the proper order' do
# rep 1
expect(Nanoc::Int::NotificationCenter).to receive(:post).with(:compilation_started, rep).ordered
expect(Nanoc::Int::NotificationCenter).to receive(:post).with(:filtering_started, rep, :erb).ordered
expect(Nanoc::Int::NotificationCenter).to receive(:post).with(:dependency_created, item, other_item).ordered
expect(Nanoc::Int::NotificationCenter).to receive(:post).with(:compilation_suspended, rep, anything).ordered
# rep 2
expect(Nanoc::Int::NotificationCenter).to receive(:post).with(:compilation_started, other_rep).ordered
expect(Nanoc::Int::NotificationCenter).to receive(:post).with(:filtering_started, other_rep, :erb).ordered
expect(Nanoc::Int::NotificationCenter).to receive(:post).with(:filtering_ended, other_rep, :erb).ordered
expect(Nanoc::Int::NotificationCenter).to receive(:post).with(:compilation_ended, other_rep).ordered
# rep 1 (again)
expect(Nanoc::Int::NotificationCenter).to receive(:post).with(:compilation_started, rep).ordered
expect(Nanoc::Int::NotificationCenter).to receive(:post).with(:filtering_ended, rep, :erb).ordered
expect(Nanoc::Int::NotificationCenter).to receive(:post).with(:compilation_ended, rep).ordered
expect { stage.send(:compile_rep, rep, phase_stack: phase_stack, is_outdated: true) }
.to raise_error(Nanoc::Int::Errors::UnmetDependency)
stage.send(:compile_rep, other_rep, phase_stack: phase_stack, is_outdated: true)
stage.send(:compile_rep, rep, phase_stack: phase_stack, is_outdated: true)
end
end
end
end
nanoc-4.11.0/nanoc/spec/nanoc/base/core_ext/000077500000000000000000000000001340050175000205365ustar00rootroot00000000000000nanoc-4.11.0/nanoc/spec/nanoc/base/core_ext/array_spec.rb000066400000000000000000000023321340050175000232130ustar00rootroot00000000000000# frozen_string_literal: true
describe 'Array#__nanoc_symbolize_keys_recursively' do
it 'should convert keys to symbols' do
array_old = [:abc, 'xyz', { 'foo' => 'bar', :baz => :qux }]
array_new = [:abc, 'xyz', { foo: 'bar', baz: :qux }]
expect(array_old.__nanoc_symbolize_keys_recursively).to eql(array_new)
end
end
describe 'Array#__nanoc_stringify_keys_recursively' do
it 'should convert keys to strings' do
array_old = [:abc, 'xyz', { 'foo' => 'bar', baz: :qux }]
array_new = [:abc, 'xyz', { 'foo' => 'bar', 'baz' => :qux }]
expect(array_old.__nanoc_stringify_keys_recursively).to eql(array_new)
end
end
describe 'Array#__nanoc_freeze_recursively' do
it 'should prevent first-level elements from being modified' do
array = [:a, %i[b c], :d]
array.__nanoc_freeze_recursively
expect { array[0] = 123 }.to raise_frozen_error
end
it 'should prevent second-level elements from being modified' do
array = [:a, %i[b c], :d]
array.__nanoc_freeze_recursively
expect { array[1][0] = 123 }.to raise_frozen_error
end
it 'should not freeze infinitely' do
a = []
a << a
a.__nanoc_freeze_recursively
expect(a).to be_frozen
expect(a[0]).to be_frozen
end
end
nanoc-4.11.0/nanoc/spec/nanoc/base/core_ext/hash_spec.rb000066400000000000000000000027061340050175000230250ustar00rootroot00000000000000# frozen_string_literal: true
describe 'Hash#__nanoc_symbolize_keys_recursively' do
it 'should convert keys to symbols' do
hash_old = { 'foo' => 'bar' }
hash_new = { foo: 'bar' }
expect(hash_old.__nanoc_symbolize_keys_recursively).to eql(hash_new)
end
it 'should not require string keys' do
hash_old = { Time.now => 'abc' }
hash_new = hash_old
expect(hash_old.__nanoc_symbolize_keys_recursively).to eql(hash_new)
end
end
describe 'Hash#__nanoc_stringify_keys_recursively' do
it 'should convert keys to strings' do
hash_old = { foo: 'bar' }
hash_new = { 'foo' => 'bar' }
expect(hash_old.__nanoc_stringify_keys_recursively).to eql(hash_new)
end
it 'should not require symbol keys' do
hash_old = { Time.now => 'abc' }
hash_new = hash_old
expect(hash_old.__nanoc_stringify_keys_recursively).to eql(hash_new)
end
end
describe 'Hash#__nanoc_freeze_recursively' do
it 'should prevent first-level elements from being modified' do
hash = { a: { b: :c } }
hash.__nanoc_freeze_recursively
expect { hash[:a] = 123 }.to raise_frozen_error
end
it 'should prevent second-level elements from being modified' do
hash = { a: { b: :c } }
hash.__nanoc_freeze_recursively
expect { hash[:a][:b] = 123 }.to raise_frozen_error
end
it 'should not freeze infinitely' do
a = {}
a[:x] = a
a.__nanoc_freeze_recursively
expect(a).to be_frozen
expect(a[0]).to be_frozen
end
end
nanoc-4.11.0/nanoc/spec/nanoc/base/core_ext/string_spec.rb000066400000000000000000000012761340050175000234110ustar00rootroot00000000000000# frozen_string_literal: true
describe 'String#__nanoc_cleaned_identifier' do
it 'should not convert already clean paths' do
expect('/foo/bar/'.__nanoc_cleaned_identifier).to eql('/foo/bar/')
end
it 'should prepend slash if necessary' do
expect('foo/bar/'.__nanoc_cleaned_identifier).to eql('/foo/bar/')
end
it 'should append slash if necessary' do
expect('/foo/bar'.__nanoc_cleaned_identifier).to eql('/foo/bar/')
end
it 'should remove double slashes at start' do
expect('//foo/bar/'.__nanoc_cleaned_identifier).to eql('/foo/bar/')
end
it 'should remove double slashes at end' do
expect('/foo/bar//'.__nanoc_cleaned_identifier).to eql('/foo/bar/')
end
end
nanoc-4.11.0/nanoc/spec/nanoc/base/directed_graph_spec.rb000066400000000000000000000140351340050175000232340ustar00rootroot00000000000000# frozen_string_literal: true
describe Nanoc::Int::DirectedGraph do
subject(:graph) { described_class.new(%w[1 2 3]) }
describe '#edges' do
subject { graph.edges }
context 'empty graph' do
it { is_expected.to be_empty }
end
context 'graph with vertices, but no edges' do
before do
graph.add_vertex('1')
graph.add_vertex('2')
end
it { is_expected.to be_empty }
end
context 'graph with edges from previously added vertices' do
before do
graph.add_vertex('1')
graph.add_vertex('2')
graph.add_vertex('3')
graph.add_edge('1', '2')
graph.add_edge('1', '3')
end
it { is_expected.to match_array([[0, 1, nil], [0, 2, nil]]) }
end
context 'graph with edges from new vertices' do
before do
graph.add_edge('1', '2')
graph.add_edge('1', '3')
end
it { is_expected.to match_array([[0, 1, nil], [0, 2, nil]]) }
end
context 'graph with edge props' do
before do
graph.add_edge('1', '2', props: { name: 'Mr. C' })
graph.add_edge('1', '3', props: { name: 'Cooper' })
end
it { is_expected.to match_array([[0, 1, { name: 'Mr. C' }], [0, 2, { name: 'Cooper' }]]) }
end
end
it 'has correct examples' do
expect('Nanoc::Int::DirectedGraph')
.to have_correct_yard_examples
.in_file('nanoc/lib/nanoc/base/entities/directed_graph.rb')
end
describe '#vertices' do
subject { graph.vertices }
it { is_expected.to include('1') }
it { is_expected.not_to include('4') }
end
describe '#add_edge' do
subject { graph.add_edge('1', '4') }
it 'adds vertex' do
expect { subject }
.to change { graph.vertices.include?('4') }
.from(false)
.to(true)
end
it 'changes direct predecessors' do
expect { subject }
.to change { graph.direct_predecessors_of('4') }
.from([])
.to(['1'])
end
end
describe '#props_for' do
subject { graph.props_for('1', '2') }
context 'no edge' do
it { is_expected.to be_nil }
end
context 'edge, but no props' do
before { graph.add_edge('1', '2') }
it { is_expected.to be_nil }
end
context 'edge with props' do
before { graph.add_edge('1', '2', props: { name: 'Mr. C' }) }
it { is_expected.to eq(name: 'Mr. C') }
context 'deleted edge (#delete_edges_to)' do
before { graph.delete_edges_to('2') }
it { is_expected.to be_nil }
end
end
end
describe '#direct_predecessors_of' do
subject { graph.direct_predecessors_of('2') }
context 'no edges' do
it { is_expected.to be_empty }
end
context 'requested for non-existant vertex' do
subject { graph.direct_predecessors_of('12345') }
it { is_expected.to be_empty }
it { is_expected.to be_a(Set) }
end
context 'one edge to' do
before { graph.add_edge('1', '2') }
it { is_expected.to match_array(['1']) }
it { is_expected.to be_a(Set) }
end
context 'two edges to' do
before do
graph.add_edge('1', '2')
graph.add_edge('3', '2')
end
it { is_expected.to match_array(%w[1 3]) }
it { is_expected.to be_a(Set) }
end
context 'edge from' do
before { graph.add_edge('2', '3') }
it { is_expected.to be_empty }
it { is_expected.to be_a(Set) }
end
end
describe '#predecessors_of' do
subject { graph.predecessors_of('2') }
context 'requested for non-existant vertex' do
subject { graph.predecessors_of('12345') }
it { is_expected.to be_empty }
it { is_expected.to be_a(Set) }
end
context 'no predecessors' do
before do
graph.add_edge('2', '3')
end
it { is_expected.to be_empty }
end
context 'direct predecessor' do
before do
graph.add_edge('2', '3')
graph.add_edge('1', '2')
end
context 'no indirect predecessors' do
it { is_expected.to match_array(['1']) }
end
context 'indirect predecessors' do
before { graph.add_edge('3', '1') }
it { is_expected.to match_array(%w[1 2 3]) }
end
end
end
describe '#delete_edges_to' do
before do
graph.add_edge('1', '2')
graph.add_edge('2', '1')
graph.add_edge('2', '3')
graph.add_edge('3', '2')
graph.add_edge('1', '3')
graph.add_edge('3', '1')
end
subject { graph.delete_edges_to('1') }
it 'deletes edges to 1' do
expect { subject }
.to change { graph.direct_predecessors_of('1') }
.from(%w[2 3])
.to([])
end
it 'keeps edges to 2' do
expect { subject }
.not_to change { graph.direct_predecessors_of('2') }
end
it 'keeps edges to 3' do
expect { subject }
.not_to change { graph.direct_predecessors_of('3') }
end
it 'keeps edges to 4' do
expect { subject }
.not_to change { graph.direct_predecessors_of('4') }
end
end
describe '#inspect' do
subject { graph.inspect }
context 'empty graph' do
it { is_expected.to eq('Nanoc::Int::DirectedGraph()') }
end
context 'one edge, no props' do
before do
graph.add_edge('1', '2')
end
it { is_expected.to eq('Nanoc::Int::DirectedGraph("1" -> "2" props=nil)') }
end
context 'two edges, no props' do
before do
graph.add_edge('1', '2')
graph.add_edge('2', '3')
end
it { is_expected.to eq('Nanoc::Int::DirectedGraph("1" -> "2" props=nil, "2" -> "3" props=nil)') }
end
context 'one edge, props' do
before do
graph.add_edge('1', '2', props: 'giraffe')
end
it { is_expected.to eq('Nanoc::Int::DirectedGraph("1" -> "2" props="giraffe")') }
end
context 'two edges, props' do
before do
graph.add_edge('1', '2', props: 'donkey')
graph.add_edge('2', '3', props: 'zebra')
end
it { is_expected.to eq('Nanoc::Int::DirectedGraph("1" -> "2" props="donkey", "2" -> "3" props="zebra")') }
end
end
end
nanoc-4.11.0/nanoc/spec/nanoc/base/entities/000077500000000000000000000000001340050175000205525ustar00rootroot00000000000000nanoc-4.11.0/nanoc/spec/nanoc/base/entities/action_sequence_spec.rb000066400000000000000000000217271340050175000252670ustar00rootroot00000000000000# frozen_string_literal: true
describe Nanoc::Int::ActionSequence do
let(:action_sequence) { raise 'override me' }
let(:item) { Nanoc::Int::Item.new('foo', {}, '/foo.md') }
let(:rep) { Nanoc::Int::ItemRep.new(item, :default) }
describe '#size' do
subject { action_sequence.size }
context 'no actions' do
let(:action_sequence) do
described_class.build(rep) do |b|
end
end
it { is_expected.to eql(0) }
end
context 'some actions' do
let(:action_sequence) do
described_class.build(rep) do |b|
b.add_filter(:foo, {})
end
end
it { is_expected.to eql(1) }
end
end
describe '#[]' do
subject { action_sequence[index] }
let(:index) { 0 }
context 'no actions' do
let(:action_sequence) do
described_class.build(rep) do |b|
end
end
it { is_expected.to be_nil }
end
context 'some actions' do
let(:action_sequence) do
described_class.build(rep) do |b|
b.add_filter(:foo, {})
end
end
it { is_expected.to be_a(Nanoc::Int::ProcessingActions::Filter) }
end
end
describe '#add_filter' do
let(:action_sequence) do
described_class.build(rep) do |b|
b.add_filter(:foo, donkey: 123)
end
end
example do
expect(action_sequence.size).to eql(1)
expect(action_sequence[0]).to be_a(Nanoc::Int::ProcessingActions::Filter)
expect(action_sequence[0].filter_name).to eql(:foo)
expect(action_sequence[0].params).to eql(donkey: 123)
end
end
describe '#add_layout' do
let(:action_sequence) do
described_class.build(rep) do |b|
b.add_layout('/foo.*', donkey: 123)
end
end
example do
expect(action_sequence.size).to eql(1)
expect(action_sequence[0]).to be_a(Nanoc::Int::ProcessingActions::Layout)
expect(action_sequence[0].layout_identifier).to eql('/foo.*')
expect(action_sequence[0].params).to eql(donkey: 123)
end
end
describe '#add_snapshot' do
context 'snapshot does not yet exist' do
let(:action_sequence) do
described_class.build(rep) do |b|
b.add_snapshot(:before_layout, '/foo.md')
end
end
example do
expect(action_sequence.size).to eql(1)
expect(action_sequence[0]).to be_a(Nanoc::Int::ProcessingActions::Snapshot)
expect(action_sequence[0].snapshot_names).to eql([:before_layout])
expect(action_sequence[0].paths).to eql(['/foo.md'])
end
end
context 'snapshot already exist' do
it 'raises' do
described_class.build(rep) do |b|
b.add_snapshot(:before_layout, '/bar.md')
expect { b.add_snapshot(:before_layout, '/foo.md') }
.to raise_error(Nanoc::Int::Errors::CannotCreateMultipleSnapshotsWithSameName)
end
end
end
end
describe '#each' do
let(:action_sequence) do
described_class.build(rep) do |b|
b.add_filter(:erb, awesomeness: 'high')
b.add_snapshot(:bar, '/foo.md')
b.add_layout('/default.erb', somelayoutparam: 'yes')
end
end
example do
actions = []
action_sequence.each { |a| actions << a }
expect(actions.size).to eq(3)
end
end
describe '#map' do
let(:action_sequence) do
described_class.build(rep) do |b|
b.add_filter(:erb, awesomeness: 'high')
b.add_snapshot(:bar, '/foo.md')
b.add_layout('/default.erb', somelayoutparam: 'yes')
end
end
example do
res = action_sequence.map { Nanoc::Int::ProcessingActions::Filter.new(:donkey, {}) }
expect(res.to_a.size).to eq(3)
expect(res.to_a).to all(be_a(Nanoc::Int::ProcessingActions::Filter))
end
end
describe '#serialize' do
subject { action_sequence.serialize }
let(:action_sequence) do
described_class.build(rep) do |b|
b.add_filter(:erb, awesomeness: 'high')
b.add_snapshot(:bar, '/foo.md')
b.add_layout('/default.erb', somelayoutparam: 'yes')
end
end
example do
expect(subject).to eql(
[
[:filter, :erb, 'PeWUm2PtXYtqeHJdTqnY7kkwAow='],
[:snapshot, [:bar], true, ['/foo.md']],
[:layout, '/default.erb', '97LAe1pYTLKczxBsu+x4MmvqdkU='],
],
)
end
end
describe '#snapshots_defs' do
let(:item) { Nanoc::Int::Item.new('asdf', {}, '/foo.md') }
let(:rep) { Nanoc::Int::ItemRep.new(item, :default) }
Class.new(Nanoc::Filter) do
identifier :RuleMemSpec_filter_b2b
type :binary => :binary # rubocop:disable Style/HashSyntax
def run(content, params = {}); end
end
Class.new(Nanoc::Filter) do
identifier :RuleMemSpec_filter_b2t
type :binary => :text # rubocop:disable Style/HashSyntax
def run(content, params = {}); end
end
Class.new(Nanoc::Filter) do
identifier :RuleMemSpec_filter_t2t
type :text => :text # rubocop:disable Style/HashSyntax
def run(content, params = {}); end
end
Class.new(Nanoc::Filter) do
identifier :RuleMemSpec_filter_t2b
type :text => :binary # rubocop:disable Style/HashSyntax
def run(content, params = {}); end
end
it 'has no snapshot defs by default' do
action_sequence =
described_class.build(rep) do |b|
end
expect(action_sequence.snapshots_defs).to be_empty
end
context 'textual item' do
let(:item) { Nanoc::Int::Item.new('asdf', {}, '/foo.md') }
it 'generates initial textual snapshot def' do
action_sequence =
described_class.build(rep) do |b|
b.add_snapshot(:giraffe, nil)
end
expect(action_sequence.snapshots_defs.size).to eq(1)
expect(action_sequence.snapshots_defs[0].name).to eq(:giraffe)
expect(action_sequence.snapshots_defs[0]).not_to be_binary
end
it 'generated follow-up textual snapshot def if previous filter is textual' do
action_sequence =
described_class.build(rep) do |b|
b.add_snapshot(:giraffe, nil)
b.add_filter(:RuleMemSpec_filter_t2t, arguments: 'irrelevant')
b.add_snapshot(:zebra, nil)
end
expect(action_sequence.snapshots_defs.size).to eq(2)
expect(action_sequence.snapshots_defs[0].name).to eq(:giraffe)
expect(action_sequence.snapshots_defs[0]).not_to be_binary
expect(action_sequence.snapshots_defs[1].name).to eq(:zebra)
expect(action_sequence.snapshots_defs[1]).not_to be_binary
end
it 'generated follow-up binary snapshot def if previous filter is text-to-bianry' do
action_sequence =
described_class.build(rep) do |b|
b.add_snapshot(:giraffe, nil)
b.add_filter(:RuleMemSpec_filter_t2b, arguments: 'irrelevant')
b.add_snapshot(:zebra, nil)
end
expect(action_sequence.snapshots_defs.size).to eq(2)
expect(action_sequence.snapshots_defs[0].name).to eq(:giraffe)
expect(action_sequence.snapshots_defs[0]).not_to be_binary
expect(action_sequence.snapshots_defs[1].name).to eq(:zebra)
expect(action_sequence.snapshots_defs[1]).to be_binary
end
end
context 'binary item' do
let(:item) { Nanoc::Int::Item.new(Nanoc::Int::BinaryContent.new('/asdf.dat'), {}, '/foo.md') }
it 'generates initial binary snapshot def' do
action_sequence =
described_class.build(rep) do |b|
b.add_snapshot(:giraffe, nil)
end
expect(action_sequence.snapshots_defs.size).to eq(1)
expect(action_sequence.snapshots_defs[0].name).to eq(:giraffe)
expect(action_sequence.snapshots_defs[0]).to be_binary
end
it 'generated follow-up binary snapshot def if previous filter is binary' do
action_sequence =
described_class.build(rep) do |b|
b.add_snapshot(:giraffe, nil)
b.add_filter(:RuleMemSpec_filter_b2b, arguments: 'irrelevant')
b.add_snapshot(:zebra, nil)
end
expect(action_sequence.snapshots_defs.size).to eq(2)
expect(action_sequence.snapshots_defs[0].name).to eq(:giraffe)
expect(action_sequence.snapshots_defs[0]).to be_binary
expect(action_sequence.snapshots_defs[1].name).to eq(:zebra)
expect(action_sequence.snapshots_defs[1]).to be_binary
end
it 'generated follow-up textual snapshot def if previous filter is binary-to-text' do
action_sequence =
described_class.build(rep) do |b|
b.add_snapshot(:giraffe, nil)
b.add_filter(:RuleMemSpec_filter_b2t, arguments: 'irrelevant')
b.add_snapshot(:zebra, nil)
end
expect(action_sequence.snapshots_defs.size).to eq(2)
expect(action_sequence.snapshots_defs[0].name).to eq(:giraffe)
expect(action_sequence.snapshots_defs[0]).to be_binary
expect(action_sequence.snapshots_defs[1].name).to eq(:zebra)
expect(action_sequence.snapshots_defs[1]).not_to be_binary
end
end
end
end
nanoc-4.11.0/nanoc/spec/nanoc/base/entities/code_snippet_spec.rb000066400000000000000000000027161340050175000245730ustar00rootroot00000000000000# frozen_string_literal: true
describe Nanoc::Int::CodeSnippet do
subject(:code_snippet) { described_class.new(data, 'lib/foo.rb') }
describe '#load' do
subject { code_snippet.load }
describe 'calling #include' do
let(:data) do
<<~EOS
module CodeSnippetSpecHelper1
def fe345b48e4
"fe345b48e4"
end
end
include CodeSnippetSpecHelper1
EOS
end
it 'makes helper functions available everywhere' do
expect { subject }
.to change { [Nanoc::Int::Context.new({}).respond_to?(:fe345b48e4), Complex.respond_to?(:fe345b48e4)] }
.from([false, false])
.to([true, true])
end
end
describe 'calling #use_helper' do
let(:data) do
<<~EOS
module CodeSnippetSpecHelper2
def e0f0c30b5e
"e0f0c30b5e"
end
end
use_helper CodeSnippetSpecHelper2
EOS
end
it 'makes helper functions available in helpers only' do
expect { subject }
.to change { [Nanoc::Int::Context.new({}).respond_to?(:e0f0c30b5e), Complex.respond_to?(:e0f0c30b5e)] }
.from([false, false])
.to([true, false])
end
end
it 'defines at top level' do
@foo = 'meow'
code_snippet = Nanoc::Int::CodeSnippet.new("@foo = 'woof'", 'dog.rb')
code_snippet.load
expect(@foo).to eq('meow')
end
end
end
nanoc-4.11.0/nanoc/spec/nanoc/base/entities/configuration_spec.rb000066400000000000000000000315641340050175000247710ustar00rootroot00000000000000# frozen_string_literal: true
describe Nanoc::Int::Configuration do
let(:hash) { { foo: 'bar' } }
let(:config) { described_class.new(hash: hash, dir: Dir.getwd) }
describe '#key?' do
subject { config.key?(key) }
context 'non-existent key' do
let(:key) { :donkey }
it { is_expected.not_to be }
end
context 'existent key' do
let(:key) { :foo }
it { is_expected.to be }
end
end
describe '#with_defaults' do
subject { config.with_defaults }
context 'no env' do
it 'has a default output_dir' do
expect(subject[:output_dir]).to eql('output')
end
end
context 'env' do
let(:config) { described_class.new(hash: hash, dir: Dir.getwd, env_name: 'giraffes') }
it 'retains the env name' do
expect(subject.env_name).to eql('giraffes')
end
end
end
describe '#output_dir' do
subject { config.with_defaults.output_dir }
context 'not explicitly defined' do
let(:hash) { { foo: 'bar' } }
it { is_expected.to eql(Dir.getwd + '/output') }
end
context 'explicitly defined, top-level' do
let(:hash) { { foo: 'bar', output_dir: 'build' } }
it { is_expected.to eql(Dir.getwd + '/build') }
end
end
describe '#output_dirs' do
subject { config.with_defaults.output_dirs }
let(:hash) do
{
output_dir: 'output_toplevel',
environments: {
default: {
output_dir: 'output_default',
},
production: {
output_dir: 'output_prod',
},
staging: {
output_dir: 'output_staging',
},
other: {},
},
}
end
it 'contains both top-level and default output dir' do
expect(subject).to include(Dir.getwd + '/output_toplevel')
expect(subject).to include(Dir.getwd + '/output_default')
end
it 'does not contain nil' do
expect(subject).not_to include(nil)
end
it 'contains all other output dirs' do
expect(subject).to include(Dir.getwd + '/output_staging')
expect(subject).to include(Dir.getwd + '/output_prod')
end
end
describe '#merge' do
let(:hash1) { { foo: { bar: 'baz', baz: ['biz'] } } }
let(:hash2) { { foo: { bar: :boz, biz: 'buz' } } }
let(:config1) { described_class.new(hash: hash1, dir: Dir.getwd) }
let(:config2) { described_class.new(hash: hash2, dir: Dir.getwd) }
subject { config1.merge(config2).to_h }
it 'contains the recursive merge of both configurations' do
expect(subject).to include(foo: { bar: :boz, baz: ['biz'], biz: 'buz' })
end
end
context 'with environments defined' do
let(:hash) { { foo: 'bar', environments: { test: { foo: 'test-bar' }, default: { foo: 'default-bar' } } } }
let(:config) { described_class.new(hash: hash, dir: Dir.getwd, env_name: env_name).with_environment }
subject { config }
context 'with existing environment' do
let(:env_name) { 'test' }
it 'inherits options from given environment' do
expect(subject[:foo]).to eq('test-bar')
end
end
context 'with unknown environment' do
let(:env_name) { 'wtf' }
it 'does not inherits options from any environment' do
expect(subject[:foo]).to eq('bar')
end
end
context 'without given environment' do
let(:env_name) { nil }
it 'inherits options from default environment' do
expect(subject[:foo]).to eq('default-bar')
end
end
end
describe 'validation' do
subject { config }
context 'valid text_extensions' do
let(:hash) { { text_extensions: ['md'] } }
it 'passes' do
expect { subject }.not_to raise_error
end
end
context 'invalid text_extensions (not an array)' do
let(:hash) { { text_extensions: 123 } }
it 'fails' do
expect { subject }.to raise_error(JsonSchema::Error)
end
end
context 'invalid text_extensions (array, but with other things)' do
let(:hash) { { text_extensions: [123] } }
it 'fails' do
expect { subject }.to raise_error(JsonSchema::Error)
end
end
context 'valid output_dir' do
let(:hash) { { output_dir: 'output' } }
it 'passes' do
expect { subject }.not_to raise_error
end
end
context 'invalid output_dir' do
let(:hash) { { output_dir: 123 } }
it 'fails' do
expect { subject }.to raise_error(JsonSchema::Error)
end
end
context 'valid index_filenames' do
let(:hash) { { index_filenames: ['index.html'] } }
it 'passes' do
expect { subject }.not_to raise_error
end
end
context 'invalid index_filenames (not an array)' do
let(:hash) { { index_filenames: 123 } }
it 'fails' do
expect { subject }.to raise_error(JsonSchema::Error)
end
end
context 'invalid index_filenames (array, but with other things)' do
let(:hash) { { index_filenames: [123] } }
it 'fails' do
expect { subject }.to raise_error(JsonSchema::Error)
end
end
context 'valid enable_output_diff' do
let(:hash) { { enable_output_diff: false } }
it 'passes' do
expect { subject }.not_to raise_error
end
end
context 'invalid enable_output_diff' do
let(:hash) { { enable_output_diff: 'nope' } }
it 'fails' do
expect { subject }.to raise_error(JsonSchema::Error)
end
end
context 'valid prune (empty)' do
let(:hash) { { prune: {} } }
it 'passes' do
expect { subject }.not_to raise_error
end
end
context 'valid prune (full)' do
let(:hash) { { prune: { auto_prune: true, exclude: ['oink'] } } }
it 'passes' do
expect { subject }.not_to raise_error
end
end
context 'invalid prune (not a hash)' do
let(:hash) { { prune: 'please' } }
it 'passes' do
expect { subject }.to raise_error(JsonSchema::Error)
end
end
context 'invalid prune (auto_prune has incorrect type)' do
let(:hash) { { prune: { auto_prune: 'please' } } }
it 'passes' do
expect { subject }.to raise_error(JsonSchema::Error)
end
end
context 'invalid prune (exclude has incorrect type)' do
let(:hash) { { prune: { exclude: 'nothing' } } }
it 'passes' do
expect { subject }.to raise_error(JsonSchema::Error)
end
end
context 'invalid prune (exclude has items of incorrect type)' do
let(:hash) { { prune: { exclude: [3000] } } }
it 'passes' do
expect { subject }.to raise_error(JsonSchema::Error)
end
end
context 'valid commands_dirs' do
let(:hash) { { commands_dirs: ['commands'] } }
it 'passes' do
expect { subject }.not_to raise_error
end
end
context 'invalid commands_dirs (not an array)' do
let(:hash) { { commands_dirs: 123 } }
it 'fails' do
expect { subject }.to raise_error(JsonSchema::Error)
end
end
context 'invalid commands_dirs (array, but with other things)' do
let(:hash) { { commands_dirs: [123] } }
it 'fails' do
expect { subject }.to raise_error(JsonSchema::Error)
end
end
context 'valid lib_dirs' do
let(:hash) { { lib_dirs: ['lib'] } }
it 'passes' do
expect { subject }.not_to raise_error
end
end
context 'invalid lib_dirs (not an array)' do
let(:hash) { { lib_dirs: 123 } }
it 'fails' do
expect { subject }.to raise_error(JsonSchema::Error)
end
end
context 'invalid lib_dirs (array, but with other things)' do
let(:hash) { { lib_dirs: [123] } }
it 'fails' do
expect { subject }.to raise_error(JsonSchema::Error)
end
end
context 'valid data_sources (full)' do
let(:hash) { { data_sources: [{ type: 'something', items_root: 'itemz/' }] } }
it 'passes' do
expect { subject }.not_to raise_error
end
end
context 'valid data_sources (null items_root)' do
let(:hash) { { data_sources: [{ type: 'something', items_root: nil }] } }
it 'passes' do
expect { subject }.not_to raise_error
end
end
context 'valid data_sources (null layouts_root)' do
let(:hash) { { data_sources: [{ type: 'something', layouts_root: nil }] } }
it 'passes' do
expect { subject }.not_to raise_error
end
end
context 'valid data_sources (empty list)' do
let(:hash) { { data_sources: [] } }
it 'passes' do
expect { subject }.not_to raise_error
end
end
context 'valid data_sources (list with empty hashes)' do
let(:hash) { { data_sources: [{}] } }
it 'passes' do
expect { subject }.not_to raise_error
end
end
context 'invalid data_sources (not an array)' do
let(:hash) { { data_sources: 'all of them please' } }
it 'fails' do
expect { subject }.to raise_error(JsonSchema::Error)
end
end
context 'invalid data_sources (items have invalid type)' do
let(:hash) { { data_sources: ['all of them please'] } }
it 'fails' do
expect { subject }.to raise_error(JsonSchema::Error)
end
end
context 'invalid data_sources (items have invalid type field)' do
let(:hash) { { data_sources: [{ type: 17 }] } }
it 'fails' do
expect { subject }.to raise_error(JsonSchema::Error)
end
end
context 'invalid data_sources (items have invalid items_root field)' do
let(:hash) { { data_sources: [{ items_root: 17 }] } }
it 'fails' do
expect { subject }.to raise_error(JsonSchema::Error)
end
end
context 'invalid data_sources (items have invalid layouts_root field)' do
let(:hash) { { data_sources: [{ layouts_root: 17 }] } }
it 'fails' do
expect { subject }.to raise_error(JsonSchema::Error)
end
end
context 'valid string_pattern_type' do
let(:hash) { { string_pattern_type: 'glob' } }
it 'passes' do
expect { subject }.not_to raise_error
end
end
context 'invalid string_pattern_type (incorrect type)' do
let(:hash) { { string_pattern_type: 16 } }
it 'fails' do
expect { subject }.to raise_error(JsonSchema::Error)
end
end
context 'invalid string_pattern_type (not in enum)' do
let(:hash) { { string_pattern_type: 'pretty' } }
it 'fails' do
expect { subject }.to raise_error(JsonSchema::Error)
end
end
context 'valid checks (full)' do
let(:hash) do
{
checks: {
internal_links: {
exclude: ['oink'],
},
external_links: {
exclude: ['abc'],
exclude_files: ['xyz'],
},
},
}
end
it 'passes' do
expect { subject }.not_to raise_error
end
end
context 'invalid checks (invalid type)' do
let(:hash) do
{ checks: 123 }
end
it 'passes' do
expect { subject }.to raise_error(JsonSchema::Error)
end
end
context 'invalid checks (internal_links has invalid type)' do
let(:hash) do
{ checks: { internal_links: 123 } }
end
it 'passes' do
expect { subject }.to raise_error(JsonSchema::Error)
end
end
context 'invalid checks (internal_links.exclude has invalid type)' do
let(:hash) do
{ checks: { internal_links: { exclude: 'everything' } } }
end
it 'passes' do
expect { subject }.to raise_error(JsonSchema::Error)
end
end
context 'invalid checks (external_links has invalid type)' do
let(:hash) do
{ checks: { external_links: 123 } }
end
it 'passes' do
expect { subject }.to raise_error(JsonSchema::Error)
end
end
context 'invalid checks (external_links.exclude has invalid type)' do
let(:hash) do
{ checks: { external_links: { exclude: 'everything' } } }
end
it 'passes' do
expect { subject }.to raise_error(JsonSchema::Error)
end
end
context 'invalid checks (external_links.exclude_files has invalid type)' do
let(:hash) do
{ checks: { external_links: { exclude_files: 'everything' } } }
end
it 'passes' do
expect { subject }.to raise_error(JsonSchema::Error)
end
end
context 'valid environments' do
let(:hash) { { environments: { production: {} } } }
it 'passes' do
expect { subject }.not_to raise_error
end
end
context 'invalid environments (not an object)' do
let(:hash) { { environments: nil } }
it 'fails' do
expect { subject }.to raise_error(JsonSchema::Error)
end
end
context 'invalid environments (values are not objects)' do
let(:hash) { { environments: { production: nil } } }
it 'fails' do
expect { subject }.to raise_error(JsonSchema::Error)
end
end
end
end
nanoc-4.11.0/nanoc/spec/nanoc/base/entities/content_spec.rb000066400000000000000000000116021340050175000235630ustar00rootroot00000000000000# frozen_string_literal: true
describe Nanoc::Int::Content do
describe '.create' do
subject { described_class.create(arg, params) }
let(:params) { {} }
context 'nil arg' do
let(:arg) { nil }
it 'raises' do
expect { subject }.to raise_error(ArgumentError)
end
end
context 'content arg' do
let(:arg) { Nanoc::Int::TextualContent.new('foo') }
it { is_expected.to eql(arg) }
end
context 'with binary: true param' do
let(:arg) { '/foo.dat' }
let(:params) { { binary: true } }
it 'returns binary content' do
expect(subject).to be_a(Nanoc::Int::BinaryContent)
expect(subject.filename).to eql('/foo.dat')
end
end
context 'with binary: false param' do
context 'with filename param' do
let(:arg) { 'foo' }
let(:params) { { binary: false, filename: '/foo.md' } }
it 'returns textual content' do
expect(subject).to be_a(Nanoc::Int::TextualContent)
expect(subject.string).to eql('foo')
expect(subject.filename).to eql('/foo.md')
end
end
context 'without filename param' do
let(:arg) { 'foo' }
let(:params) { { binary: false } }
it 'returns textual content' do
expect(subject).to be_a(Nanoc::Int::TextualContent)
expect(subject.string).to eql('foo')
expect(subject.filename).to be_nil
end
end
end
end
end
describe Nanoc::Int::TextualContent do
describe '#initialize' do
context 'without filename' do
let(:content) { described_class.new('foo') }
it 'sets string and filename' do
expect(content.string).to eq('foo')
expect(content.filename).to be_nil
end
end
context 'with absolute filename' do
let(:content) { described_class.new('foo', filename: '/foo.md') }
it 'sets string and filename' do
expect(content.string).to eq('foo')
expect(content.filename).to eq('/foo.md')
end
end
context 'with relative filename' do
let(:content) { described_class.new('foo', filename: 'foo.md') }
it 'errors' do
expect { content }.to raise_error(ArgumentError)
end
end
context 'with proc' do
let(:content_proc) { -> { 'foo' } }
let(:content) { described_class.new(content_proc) }
it 'does not call the proc immediately' do
expect(content_proc).not_to receive(:call)
content
end
it 'sets string' do
expect(content_proc).to receive(:call).once.and_return('dataz')
expect(content.string).to eq('dataz')
end
it 'only calls the proc once' do
expect(content_proc).to receive(:call).once.and_return('dataz')
expect(content.string).to eq('dataz')
expect(content.string).to eq('dataz')
end
end
end
describe '#binary?' do
subject { content.binary? }
let(:content) { described_class.new('foo') }
it { is_expected.to eql(false) }
end
describe '#freeze' do
let(:content) { described_class.new('foo', filename: '/asdf.md') }
before do
content.freeze
end
it 'prevents changes to string' do
expect(content.string).to be_frozen
expect { content.string << 'asdf' }.to raise_frozen_error
end
it 'prevents changes to filename' do
expect(content.filename).to be_frozen
expect { content.filename << 'asdf' }.to raise_frozen_error
end
context 'with proc' do
let(:content) { described_class.new(proc { 'foo' }) }
it 'prevents changes to string' do
expect(content.string).to be_frozen
expect { content.string << 'asdf' }.to raise_frozen_error
end
end
end
describe 'marshalling' do
let(:content) { described_class.new('foo', filename: '/foo.md') }
it 'dumps as an array' do
expect(content.marshal_dump).to eq(['/foo.md', 'foo'])
end
it 'restores a dumped object' do
restored = Marshal.load(Marshal.dump(content))
expect(restored.string).to eq('foo')
expect(restored.filename).to eq('/foo.md')
end
end
end
describe Nanoc::Int::BinaryContent do
describe '#initialize' do
let(:content) { described_class.new('/foo.dat') }
it 'sets filename' do
expect(content.filename).to eql('/foo.dat')
end
context 'with relative filename' do
let(:content) { described_class.new('foo.dat') }
it 'errors' do
expect { content }.to raise_error(ArgumentError)
end
end
end
describe '#binary?' do
subject { content.binary? }
let(:content) { described_class.new('/foo.dat') }
it { is_expected.to eql(true) }
end
describe '#freeze' do
let(:content) { described_class.new('/foo.dat') }
before do
content.freeze
end
it 'prevents changes' do
expect(content.filename).to be_frozen
expect { content.filename << 'asdf' }.to raise_frozen_error
end
end
end
nanoc-4.11.0/nanoc/spec/nanoc/base/entities/context_spec.rb000066400000000000000000000012731340050175000236000ustar00rootroot00000000000000# frozen_string_literal: true
describe Nanoc::Int::Context do
let(:context) do
Nanoc::Int::Context.new(foo: 'bar', baz: 'quux')
end
it 'provides instance variables' do
expect(eval('@foo', context.get_binding)).to eq('bar')
end
it 'provides instance methods' do
expect(eval('foo', context.get_binding)).to eq('bar')
end
it 'supports #include' do
eval('include Nanoc::Helpers::HTMLEscape', context.get_binding)
expect(eval('h("<>")', context.get_binding)).to eq('<>')
end
it 'has correct examples' do
expect('Nanoc::Int::Context#initialize')
.to have_correct_yard_examples
.in_file('nanoc/lib/nanoc/base/entities/context.rb')
end
end
nanoc-4.11.0/nanoc/spec/nanoc/base/entities/document_spec.rb000066400000000000000000000225451340050175000237370ustar00rootroot00000000000000# frozen_string_literal: true
shared_examples 'a document' do
describe '#initialize' do
let(:content_arg) { 'Hello world' }
let(:attributes_arg) { { 'title' => 'Home' } }
let(:identifier_arg) { '/home.md' }
let(:checksum_data_arg) { 'abcdef' }
let(:content_checksum_data_arg) { 'con-cs' }
let(:attributes_checksum_data_arg) { 'attr-cs' }
subject do
described_class.new(
content_arg,
attributes_arg,
identifier_arg,
checksum_data: checksum_data_arg,
content_checksum_data: content_checksum_data_arg,
attributes_checksum_data: attributes_checksum_data_arg,
)
end
describe 'content arg' do
context 'string' do
it 'converts content' do
expect(subject.content).to be_a(Nanoc::Int::TextualContent)
expect(subject.content.string).to eql('Hello world')
end
end
context 'content' do
let(:content_arg) { Nanoc::Int::TextualContent.new('foo') }
it 'reuses content' do
expect(subject.content).to equal(content_arg)
end
end
end
describe 'attributes arg' do
context 'hash' do
it 'symbolizes attributes' do
expect(subject.attributes).to eq(title: 'Home')
end
end
context 'proc' do
call_count = 0
let(:attributes_arg) do
proc do
call_count += 1
{ 'title' => 'Home' }
end
end
before do
call_count = 0
end
it 'does not call the proc immediately' do
expect(call_count).to eql(0)
end
it 'symbolizes attributes' do
expect(subject.attributes).to eq(title: 'Home')
end
it 'only calls the proc once' do
subject.attributes
subject.attributes
expect(call_count).to eql(1)
end
end
end
describe 'identifier arg' do
context 'string' do
it 'converts identifier' do
expect(subject.identifier).to be_a(Nanoc::Identifier)
expect(subject.identifier.to_s).to eql('/home.md')
end
end
context 'identifier' do
let(:identifier_arg) { Nanoc::Identifier.new('/foo.md') }
it 'retains identifier' do
expect(subject.identifier).to equal(identifier_arg)
end
end
end
describe 'checksum_data arg' do
it 'reuses checksum_data' do
expect(subject.checksum_data).to eql(checksum_data_arg)
end
end
describe 'content_checksum_data arg' do
it 'reuses content_checksum_data' do
expect(subject.content_checksum_data).to eql(content_checksum_data_arg)
end
end
describe 'attributes_checksum_data arg' do
it 'reuses attributes_checksum_data' do
expect(subject.attributes_checksum_data).to eql(attributes_checksum_data_arg)
end
end
end
describe '#freeze' do
let(:content_arg) { 'Hallo' }
let(:attributes_arg) { { foo: { bar: 'asdf' } } }
let(:document) { described_class.new(content_arg, attributes_arg, '/foo.md') }
before do
document.freeze
end
it 'refuses changes to content' do
expect { document.instance_variable_set(:@content, 'hah') }.to raise_frozen_error
expect { document.content.string << 'hah' }.to raise_frozen_error
end
it 'refuses to change attributes' do
expect { document.instance_variable_set(:@attributes, a: 'Hi') }.to raise_frozen_error
expect { document.attributes[:title] = 'Bye' }.to raise_frozen_error
expect { document.attributes[:foo][:bar] = 'fdsa' }.to raise_frozen_error
end
it 'refuses to change identifier' do
expect { document.identifier = '/asdf' }.to raise_frozen_error
expect { document.identifier.to_s << '/omg' }.to raise_frozen_error
end
context 'binary content' do
let(:content_arg) { Nanoc::Int::BinaryContent.new(File.expand_path('foo.dat')) }
it 'refuses changes to content' do
expect { document.instance_variable_set(:@content, 'hah') }.to raise_frozen_error
expect { document.content.filename << 'hah' }.to raise_frozen_error
end
end
context 'attributes block' do
let(:attributes_arg) { proc { { foo: { bar: 'asdf' } } } }
it 'gives access to the attributes' do
expect(document.attributes).to eql(foo: { bar: 'asdf' })
end
it 'refuses to change attributes' do
expect { document.instance_variable_set(:@attributes, a: 'Hi') }.to raise_frozen_error
expect { document.attributes[:title] = 'Bye' }.to raise_frozen_error
expect { document.attributes[:foo][:bar] = 'fdsa' }.to raise_frozen_error
end
end
end
describe 'equality' do
let(:content_arg_a) { 'Hello world' }
let(:content_arg_b) { 'Bye world' }
let(:attributes_arg_a) { { 'title' => 'Home' } }
let(:attributes_arg_b) { { 'title' => 'About' } }
let(:identifier_arg_a) { '/home.md' }
let(:identifier_arg_b) { '/home.md' }
let(:document_a) { described_class.new(content_arg_a, attributes_arg_a, identifier_arg_a) }
let(:document_b) { described_class.new(content_arg_b, attributes_arg_b, identifier_arg_b) }
subject { document_a == document_b }
context 'same identifier' do
let(:identifier_arg_a) { '/home.md' }
let(:identifier_arg_b) { '/home.md' }
it { is_expected.to eql(true) }
it 'has same hashes' do
expect(document_a.hash).to eql(document_b.hash)
end
end
context 'different identifier' do
let(:identifier_arg_a) { '/home.md' }
let(:identifier_arg_b) { '/about.md' }
it { is_expected.to eql(false) }
it 'has different hashes' do
expect(document_a.hash).not_to eql(document_b.hash)
end
end
context 'comparing with non-document' do
let(:document_b) { nil }
it { is_expected.to eql(false) }
it 'has different hashes' do
expect(document_a.hash).not_to eql(document_b.hash)
end
end
end
describe '#with_identifier_prefix' do
let(:document) { described_class.new('kontent', { at: 'ribut' }, '/donkey.md') }
subject { document.with_identifier_prefix('/animals') }
it 'does not mutate the original' do
document.freeze
subject
end
it 'returns a new document with a prefixed identifier' do
expect(subject.identifier).to eq('/animals/donkey.md')
end
it 'does not change other data' do
expect(subject.content).to be_some_textual_content('kontent')
expect(subject.attributes).to eq(at: 'ribut')
end
end
describe '#identifier=' do
let(:document) { described_class.new('stuff', {}, '/foo.md') }
it 'allows changing to a string that contains a full identifier' do
expect { document.identifier = '/thing' }.not_to raise_error
expect(document.identifier).to eq('/thing')
expect(document.identifier).to be_full
end
it 'refuses changing to a string that does not contain a full identifier' do
expect { document.identifier = '/thing/' }
.to raise_error(Nanoc::Identifier::InvalidFullIdentifierError)
end
it 'allos changing to a full identifier' do
document.identifier = Nanoc::Identifier.new('/thing')
expect(document.identifier.to_s).to eq('/thing')
expect(document.identifier).to be_full
end
it 'allos changing to a legacy identifier' do
document.identifier = Nanoc::Identifier.new('/thing/', type: :legacy)
expect(document.identifier).to eq('/thing/')
expect(document.identifier).to be_legacy
end
end
describe '#content=' do
let(:document) do
described_class.new(
content_arg,
attributes_arg,
'/foo.md',
checksum_data: 'ch3cksum_d4t4',
content_checksum_data: 'c0nt3nt_ch3cksum_d4t4',
attributes_checksum_data: '4ttr_ch3cksum_d4t4',
)
end
let(:content_arg) { 'Hallo' }
let(:attributes_arg) { { foo: { bar: 'asdf' } } }
subject { document.content = Nanoc::Int::TextualContent.new('New!') }
it 'clears checksum' do
expect { subject }
.to change { document.checksum_data }
.from('ch3cksum_d4t4')
.to(nil)
end
it 'clears content checksum' do
expect { subject }
.to change { document.content_checksum_data }
.from('c0nt3nt_ch3cksum_d4t4')
.to(nil)
end
it 'does not clear attributes checksum data' do
expect { subject }
.not_to change { document.attributes_checksum_data }
end
end
describe '#set_attribute' do
let(:document) do
described_class.new(
content_arg,
attributes_arg,
'/foo.md',
checksum_data: 'ch3cksum_d4t4',
content_checksum_data: 'c0nt3nt_ch3cksum_d4t4',
attributes_checksum_data: '4ttr_ch3cksum_d4t4',
)
end
let(:content_arg) { 'Hallo' }
let(:attributes_arg) { { foo: { bar: 'asdf' } } }
subject { document.set_attribute(:key, 'value') }
it 'clears checksum' do
expect { subject }
.to change { document.checksum_data }
.from('ch3cksum_d4t4')
.to(nil)
end
it 'clears attributes checksum' do
expect { subject }
.to change { document.attributes_checksum_data }
.from('4ttr_ch3cksum_d4t4')
.to(nil)
end
it 'does not clear content checksum data' do
expect { subject }
.not_to change { document.content_checksum_data }
end
end
end
nanoc-4.11.0/nanoc/spec/nanoc/base/entities/identifiable_collection_spec.rb000066400000000000000000000140661340050175000267520ustar00rootroot00000000000000# frozen_string_literal: true
describe Nanoc::Int::IdentifiableCollection do
shared_examples 'a generic identifiable collection' do
subject(:identifiable_collection) { described_class.new(config, objects) }
let(:config) { Nanoc::Int::Configuration.new(dir: Dir.getwd) }
let(:objects) { [] }
describe '#reject' do
subject { identifiable_collection.reject { |_| false } }
it { is_expected.to be_a(described_class) }
end
describe '#inspect' do
subject { identifiable_collection.inspect }
it { is_expected.to eq("<#{described_class}>") }
end
describe '#[]' do
let(:objects) do
[
Nanoc::Int::Item.new('asdf', {}, Nanoc::Identifier.new('/one')),
Nanoc::Int::Item.new('asdf', {}, Nanoc::Identifier.new('/two')),
]
end
context 'string pattern style is glob' do
let(:config) { Nanoc::Int::Configuration.new(dir: Dir.getwd).with_defaults }
it 'handles glob' do
expect(identifiable_collection['/on*']).to equal(objects[0])
expect(identifiable_collection['/*wo']).to equal(objects[1])
end
end
context 'string pattern style is glob' do
let(:config) { Nanoc::Int::Configuration.new(dir: Dir.getwd) }
it 'does not handle glob' do
expect(identifiable_collection['/on*']).to be_nil
expect(identifiable_collection['/*wo']).to be_nil
end
end
it 'handles identifier' do
expect(identifiable_collection['/one']).to equal(objects[0])
expect(identifiable_collection['/two']).to equal(objects[1])
end
it 'handles malformed identifier' do
expect(identifiable_collection['one/']).to be_nil
expect(identifiable_collection['/one/']).to be_nil
expect(identifiable_collection['one']).to be_nil
expect(identifiable_collection['//one']).to be_nil
expect(identifiable_collection['/one//']).to be_nil
end
it 'handles regex' do
expect(identifiable_collection[/one/]).to equal(objects[0])
expect(identifiable_collection[/on/]).to equal(objects[0])
expect(identifiable_collection[/\/o/]).to equal(objects[0])
expect(identifiable_collection[/e$/]).to equal(objects[0])
end
context 'frozen' do
before { identifiable_collection.freeze }
example do
expect(identifiable_collection['/one']).to equal(objects[0])
expect(identifiable_collection['/fifty']).to be_nil
end
end
end
describe '#find_all' do
let(:objects) do
[
double(:identifiable, identifier: Nanoc::Identifier.new('/about.css')),
double(:identifiable, identifier: Nanoc::Identifier.new('/about.md')),
double(:identifiable, identifier: Nanoc::Identifier.new('/style.css')),
]
end
let(:arg) { raise 'override me' }
subject { identifiable_collection.find_all(arg) }
context 'with string' do
let(:arg) { '/*.css' }
it 'contains objects' do
expect(subject.size).to eql(2)
expect(subject.find { |iv| iv.identifier == '/about.css' }).to eq(objects[0])
expect(subject.find { |iv| iv.identifier == '/style.css' }).to eq(objects[2])
end
end
context 'with regex' do
let(:arg) { %r{\.css\z} }
it 'contains objects' do
expect(subject.size).to eql(2)
expect(subject.find { |iv| iv.identifier == '/about.css' }).to eq(objects[0])
expect(subject.find { |iv| iv.identifier == '/style.css' }).to eq(objects[2])
end
end
end
describe '#object_with_identifier' do
let(:objects) do
[
Nanoc::Int::Item.new('stuff', {}, Nanoc::Identifier.new('/about.css')),
Nanoc::Int::Item.new('stuff', {}, Nanoc::Identifier.new('/about.md')),
Nanoc::Int::Item.new('stuff', {}, Nanoc::Identifier.new('/style.css')),
]
end
let(:arg) { raise 'override me' }
subject { identifiable_collection.object_with_identifier(arg) }
context 'with string' do
let(:arg) { '/about.css' }
it { is_expected.to eq(objects[0]) }
end
context 'with identifier' do
let(:arg) { Nanoc::Identifier.new('/about.css') }
it { is_expected.to eq(objects[0]) }
end
context 'with glob string' do
let(:arg) { '/about.*' }
it { is_expected.to be_nil }
end
end
describe '#reference' do
subject { identifiable_collection.reference }
it { is_expected.to eql(expected_reference) }
end
describe 'changing identifiers' do
let(:objects) do
[
Nanoc::Int::Item.new('Foo', {}, '/foo'),
]
end
subject { objects[0].identifier = '/bar' }
it 'makes /foo nil' do
expect { subject }
.to change { identifiable_collection['/foo'] }
.from(objects[0])
.to(nil)
end
it 'makes /bar non-nil' do
expect { subject }
.to change { identifiable_collection['/bar'] }
.from(nil)
.to(objects[0])
end
end
describe '#each' do
let(:objects) do
[
Nanoc::Int::Item.new('Foo', {}, '/foo'),
Nanoc::Int::Item.new('Bar', {}, '/bar'),
]
end
it 'loops' do
res = []
identifiable_collection.each { |i| res << i.identifier.to_s }
expect(res).to match_array(['/foo', '/bar'])
end
end
describe '#map' do
let(:objects) do
[
Nanoc::Int::Item.new('Foo', {}, '/foo'),
Nanoc::Int::Item.new('Bar', {}, '/bar'),
]
end
it 'loops' do
res = identifiable_collection.map { |i| i.identifier.to_s }
expect(res).to match_array(['/foo', '/bar'])
end
end
end
describe Nanoc::Int::ItemCollection do
let(:expected_reference) { 'items' }
it_behaves_like 'a generic identifiable collection'
end
describe Nanoc::Int::LayoutCollection do
let(:expected_reference) { 'layouts' }
it_behaves_like 'a generic identifiable collection'
end
end
nanoc-4.11.0/nanoc/spec/nanoc/base/entities/identifier_spec.rb000066400000000000000000000327611340050175000242440ustar00rootroot00000000000000# frozen_string_literal: true
describe Nanoc::Identifier do
describe '.from' do
subject { described_class.from(arg) }
context 'given an identifier' do
let(:arg) { Nanoc::Identifier.new('/foo.md') }
it 'returns an identifier' do
expect(subject).to be_a(Nanoc::Identifier)
expect(subject.to_s).to eq('/foo.md')
expect(subject).to be_full
end
end
context 'given a string' do
let(:arg) { '/foo.md' }
it 'returns an identifier' do
expect(subject).to be_a(Nanoc::Identifier)
expect(subject.to_s).to eq('/foo.md')
expect(subject).to be_full
end
end
context 'given something else' do
let(:arg) { 12_345 }
it 'raises' do
expect { subject }.to raise_error(Nanoc::Identifier::NonCoercibleObjectError)
end
end
end
describe '#initialize' do
context 'legacy type' do
it 'does not convert already clean paths' do
expect(described_class.new('/foo/bar/', type: :legacy).to_s).to eql('/foo/bar/')
end
it 'prepends slash if necessary' do
expect(described_class.new('foo/bar/', type: :legacy).to_s).to eql('/foo/bar/')
end
it 'appends slash if necessary' do
expect(described_class.new('/foo/bar', type: :legacy).to_s).to eql('/foo/bar/')
end
it 'removes double slashes at start' do
expect(described_class.new('//foo/bar/', type: :legacy).to_s).to eql('/foo/bar/')
end
it 'removes double slashes at end' do
expect(described_class.new('/foo/bar//', type: :legacy).to_s).to eql('/foo/bar/')
end
it 'freezes' do
identifier = described_class.new('/foo/bar/', type: :legacy)
expect { identifier.to_s << 'bbq' }.to raise_frozen_error
end
end
context 'full type' do
it 'refuses string not starting with a slash' do
expect { described_class.new('foo') }
.to raise_error(Nanoc::Identifier::InvalidIdentifierError)
end
it 'refuses string ending with a slash' do
expect { described_class.new('/foo/') }
.to raise_error(Nanoc::Identifier::InvalidFullIdentifierError)
end
it 'refuses string with only slash' do
expect { described_class.new('/') }
.to raise_error(Nanoc::Identifier::InvalidFullIdentifierError)
end
it 'has proper string representation' do
expect(described_class.new('/foo').to_s).to eql('/foo')
end
it 'freezes' do
identifier = described_class.new('/foo/bar')
expect { identifier.to_s << 'bbq' }.to raise_frozen_error
end
end
context 'other type' do
it 'errors' do
expect { described_class.new('foo', type: :donkey) }
.to raise_error(Nanoc::Identifier::InvalidTypeError)
end
end
context 'default type' do
it 'is full' do
expect(described_class.new('/foo')).to be_full
end
end
context 'other args specified' do
it 'errors' do
expect { described_class.new('?', animal: :donkey) }
.to raise_error(ArgumentError)
end
end
end
describe '#to_s' do
it 'returns immutable string' do
expect { described_class.new('foo/', type: :legacy).to_s << 'lols' }.to raise_frozen_error
expect { described_class.new('/foo').to_s << 'lols' }.to raise_frozen_error
end
end
describe '#to_str' do
it 'returns immutable string' do
expect { described_class.new('/foo/bar').to_str << 'lols' }.to raise_frozen_error
end
end
describe 'Comparable' do
it 'can be compared' do
expect(described_class.new('/foo/bar') <= '/qux').to eql(true)
end
end
describe '#inspect' do
let(:identifier) { described_class.new('/foo/bar') }
subject { identifier.inspect }
it { should == '' }
end
describe '#== and #eql?' do
context 'comparing with equal identifier' do
let(:identifier_a) { described_class.new('//foo/bar/', type: :legacy) }
let(:identifier_b) { described_class.new('/foo/bar//', type: :legacy) }
it 'is ==' do
expect(identifier_a).to eq(identifier_b)
end
it 'is eql?' do
expect(identifier_a).to eql(identifier_b)
end
end
context 'comparing with equal string' do
let(:identifier_a) { described_class.new('//foo/bar/', type: :legacy) }
let(:identifier_b) { '/foo/bar/' }
it 'is ==' do
expect(identifier_a).to eq(identifier_b.to_s)
end
it 'is not eql?' do
expect(identifier_a).not_to eql(identifier_b.to_s)
end
end
context 'comparing with different identifier' do
let(:identifier_a) { described_class.new('//foo/bar/', type: :legacy) }
let(:identifier_b) { described_class.new('/baz/qux//', type: :legacy) }
it 'is not ==' do
expect(identifier_a).not_to eq(identifier_b)
end
it 'is not eql?' do
expect(identifier_a).not_to eql(identifier_b)
end
end
context 'comparing with different string' do
let(:identifier_a) { described_class.new('//foo/bar/', type: :legacy) }
let(:identifier_b) { '/baz/qux/' }
it 'is not equal' do
expect(identifier_a).not_to eq(identifier_b)
end
it 'is not eql?' do
expect(identifier_a).not_to eql(identifier_b)
end
end
context 'comparing with something that is not an identifier' do
let(:identifier_a) { described_class.new('//foo/bar/', type: :legacy) }
let(:identifier_b) { :donkey }
it 'is not equal' do
expect(identifier_a).not_to eq(identifier_b)
expect(identifier_a).not_to eql(identifier_b)
end
end
end
describe '#hash' do
context 'equal identifiers' do
let(:identifier_a) { described_class.new('//foo/bar/', type: :legacy) }
let(:identifier_b) { described_class.new('/foo/bar//', type: :legacy) }
it 'is the same' do
expect(identifier_a.hash == identifier_b.hash).to eql(true)
end
end
context 'different identifiers' do
let(:identifier_a) { described_class.new('//foo/bar/', type: :legacy) }
let(:identifier_b) { described_class.new('/monkey/', type: :legacy) }
it 'is different' do
expect(identifier_a.hash == identifier_b.hash).to eql(false)
end
end
end
describe '#=~' do
let(:identifier) { described_class.new('/foo/bar') }
subject { identifier =~ pat }
context 'given a regex' do
context 'matching regex' do
let(:pat) { %r{\A/foo/bar} }
it { is_expected.to eql(0) }
end
context 'non-matching regex' do
let(:pat) { %r{\A/qux/monkey} }
it { is_expected.to eql(nil) }
end
end
context 'given a string' do
context 'matching string' do
let(:pat) { '/foo/*' }
it { is_expected.to eql(0) }
end
context 'non-matching string' do
let(:pat) { '/qux/*' }
it { is_expected.to eql(nil) }
end
end
end
describe '#match?' do
let(:identifier) { described_class.new('/foo/bar') }
subject { identifier.match?(pat) }
context 'given a regex' do
context 'matching regex' do
let(:pat) { %r{\A/foo/bar} }
it { is_expected.to be(true) }
example { expect { subject }.not_to change { Regexp.last_match } }
end
context 'non-matching regex' do
let(:pat) { %r{\A/qux/monkey} }
it { is_expected.to be(false) }
example { expect { subject }.not_to change { Regexp.last_match } }
end
end
context 'given a string' do
context 'matching string' do
let(:pat) { '/foo/*' }
it { is_expected.to be(true) }
example { expect { subject }.not_to change { Regexp.last_match } }
end
context 'non-matching string' do
let(:pat) { '/qux/*' }
it { is_expected.to be(false) }
example { expect { subject }.not_to change { Regexp.last_match } }
end
end
end
describe '#<=>' do
let(:identifier) { described_class.new('/foo/bar') }
it 'compares by string' do
expect(identifier <=> '/foo/aarghh').to eql(1)
expect(identifier <=> '/foo/bar').to eql(0)
expect(identifier <=> '/foo/qux').to eql(-1)
end
end
describe '#prefix' do
let(:identifier) { described_class.new('/foo') }
subject { identifier.prefix(prefix) }
context 'prefix not ending nor starting with a slash' do
let(:prefix) { 'asdf' }
it 'raises an error' do
expect { subject }.to raise_error(
Nanoc::Identifier::InvalidPrefixError,
'Invalid prefix (does not start with a slash): "asdf"',
)
end
end
context 'prefix ending with a slash' do
let(:prefix) { 'asdf/' }
it 'raises an error' do
expect { subject }.to raise_error(
Nanoc::Identifier::InvalidPrefixError,
'Invalid prefix (does not start with a slash): "asdf/"',
)
end
end
context 'prefix ending and starting with a slash' do
let(:prefix) { '/asdf/' }
it 'returns a proper new identifier' do
expect(subject).to be_a(Nanoc::Identifier)
expect(subject.to_s).to eql('/asdf/foo')
end
end
context 'prefix nstarting with a slash' do
let(:prefix) { '/asdf' }
it 'returns a proper new identifier' do
expect(subject).to be_a(Nanoc::Identifier)
expect(subject.to_s).to eql('/asdf/foo')
end
end
end
describe '#without_ext' do
subject { identifier.without_ext }
context 'legacy type' do
let(:identifier) { described_class.new('/foo/', type: :legacy) }
it 'raises an error' do
expect { subject }.to raise_error(Nanoc::Identifier::UnsupportedLegacyOperationError)
end
end
context 'identifier with no extension' do
let(:identifier) { described_class.new('/foo') }
it 'does nothing' do
expect(subject).to eql('/foo')
end
end
context 'identifier with extension' do
let(:identifier) { described_class.new('/foo.md') }
it 'removes the extension' do
expect(subject).to eql('/foo')
end
end
end
describe '#ext' do
subject { identifier.ext }
context 'legacy type' do
let(:identifier) { described_class.new('/foo/', type: :legacy) }
it 'raises an error' do
expect { subject }.to raise_error(Nanoc::Identifier::UnsupportedLegacyOperationError)
end
end
context 'identifier with no extension' do
let(:identifier) { described_class.new('/foo') }
it { is_expected.to be_nil }
end
context 'identifier with extension' do
let(:identifier) { described_class.new('/foo.md') }
it { is_expected.to eql('md') }
end
end
describe '#without_exts' do
subject { identifier.without_exts }
context 'legacy type' do
let(:identifier) { described_class.new('/foo/', type: :legacy) }
it 'raises an error' do
expect { subject }.to raise_error(Nanoc::Identifier::UnsupportedLegacyOperationError)
end
end
context 'identifier with no extension' do
let(:identifier) { described_class.new('/foo') }
it 'does nothing' do
expect(subject).to eql('/foo')
end
end
context 'identifier with one extension' do
let(:identifier) { described_class.new('/foo.md') }
it 'removes the extension' do
expect(subject).to eql('/foo')
end
end
context 'identifier with multiple extensions' do
let(:identifier) { described_class.new('/foo.html.md') }
it 'removes the extension' do
expect(subject).to eql('/foo')
end
end
end
describe '#exts' do
subject { identifier.exts }
context 'legacy type' do
let(:identifier) { described_class.new('/foo/', type: :legacy) }
it 'raises an error' do
expect { subject }.to raise_error(Nanoc::Identifier::UnsupportedLegacyOperationError)
end
end
context 'identifier with no extension' do
let(:identifier) { described_class.new('/foo') }
it { is_expected.to be_empty }
end
context 'identifier with one extension' do
let(:identifier) { described_class.new('/foo.md') }
it { is_expected.to eql(['md']) }
end
context 'identifier with multiple extensions' do
let(:identifier) { described_class.new('/foo.html.md') }
it { is_expected.to eql(%w[html md]) }
end
end
describe '#legacy?' do
subject { identifier.legacy? }
context 'legacy type' do
let(:identifier) { described_class.new('/foo/', type: :legacy) }
it { is_expected.to eql(true) }
end
context 'full type' do
let(:identifier) { described_class.new('/foo', type: :full) }
it { is_expected.to eql(false) }
end
end
describe '#full?' do
subject { identifier.full? }
context 'legacy type' do
let(:identifier) { described_class.new('/foo/', type: :legacy) }
it { is_expected.to eql(false) }
end
context 'full type' do
let(:identifier) { described_class.new('/foo', type: :full) }
it { is_expected.to eql(true) }
end
end
describe '#components' do
subject { identifier.components }
context 'no components' do
let(:identifier) { described_class.new('/', type: :legacy) }
it { is_expected.to eql([]) }
end
context 'one component' do
let(:identifier) { described_class.new('/foo.md') }
it { is_expected.to eql(['foo.md']) }
end
context 'two components' do
let(:identifier) { described_class.new('/foo/bar.md') }
it { is_expected.to eql(['foo', 'bar.md']) }
end
end
end
nanoc-4.11.0/nanoc/spec/nanoc/base/entities/item_rep_spec.rb000066400000000000000000000012121340050175000237110ustar00rootroot00000000000000# frozen_string_literal: true
describe Nanoc::Int::ItemRep do
let(:item) { Nanoc::Int::Item.new('asdf', {}, '/foo.md') }
let(:rep) { Nanoc::Int::ItemRep.new(item, :giraffe) }
describe '#snapshot?' do
subject { rep.snapshot?(snapshot_name) }
let(:snapshot_name) { raise 'override me' }
before do
rep.snapshot_defs = [Nanoc::Int::SnapshotDef.new(:donkey, binary: false)]
end
context 'snapshot does not exist' do
let(:snapshot_name) { :giraffe }
it { is_expected.not_to be }
end
context 'snapshot exists' do
let(:snapshot_name) { :donkey }
it { is_expected.to be }
end
end
end
nanoc-4.11.0/nanoc/spec/nanoc/base/entities/item_spec.rb000066400000000000000000000004371340050175000230530ustar00rootroot00000000000000# frozen_string_literal: true
describe Nanoc::Int::Item do
it_behaves_like 'a document'
describe '#reference' do
let(:item) { described_class.new('hi', {}, '/foo.md') }
it 'has the proper reference' do
expect(item.reference).to eql('item:/foo.md')
end
end
end
nanoc-4.11.0/nanoc/spec/nanoc/base/entities/layout_spec.rb000066400000000000000000000004471340050175000234330ustar00rootroot00000000000000# frozen_string_literal: true
describe Nanoc::Int::Layout do
it_behaves_like 'a document'
describe '#reference' do
let(:layout) { described_class.new('hi', {}, '/foo.md') }
it 'has the proper reference' do
expect(layout.reference).to eql('layout:/foo.md')
end
end
end
nanoc-4.11.0/nanoc/spec/nanoc/base/entities/lazy_value_spec.rb000066400000000000000000000065611340050175000242740ustar00rootroot00000000000000# frozen_string_literal: true
describe Nanoc::Int::LazyValue do
describe '#value' do
let(:value_arg) { +'Hello world' }
let(:lazy_value) { described_class.new(value_arg) }
subject { lazy_value.value }
context 'object' do
it { is_expected.to equal(value_arg) }
end
context 'proc' do
it 'does not call the proc immediately' do
expect(value_arg).not_to receive(:call)
lazy_value
end
it 'returns proc return value' do
expect(value_arg).to receive(:call).once.and_return('Hello proc')
expect(subject).to eql('Hello proc')
end
it 'only calls the proc once' do
expect(value_arg).to receive(:call).once.and_return('Hello proc')
expect(subject).to eql('Hello proc')
expect(subject).to eql('Hello proc')
end
end
end
describe '#map' do
let(:value_arg) { -> { 'Hello world' } }
let(:lazy_value) { described_class.new(value_arg) }
subject { lazy_value.map(&:upcase) }
it 'does not call the proc immediately' do
expect(value_arg).not_to receive(:call)
subject
end
it 'returns proc return value' do
expect(value_arg).to receive(:call).once.and_return('Hello proc')
expect(subject.value).to eql('HELLO PROC')
end
it 'only calls the proc once' do
expect(value_arg).to receive(:call).once.and_return('Hello proc')
expect(subject.value).to eql('HELLO PROC')
expect(subject.value).to eql('HELLO PROC')
end
end
describe '#freeze' do
let(:value_arg) { 'Hello world' }
subject { described_class.new(value_arg) }
context 'freeze before calling #value' do
before do
subject.freeze
end
context 'object' do
it 'returns value' do
expect(subject.value).to equal(value_arg)
end
it 'freezes value' do
expect(subject.value).to be_frozen
end
end
context 'proc' do
call_count = 0
let(:value_arg) do
proc do
call_count += 1
'Hello proc'
end
end
before do
call_count = 0
subject.freeze
end
it 'does not call the proc immediately' do
expect(call_count).to eql(0)
end
it 'returns proc return value' do
expect(subject.value).to eq('Hello proc')
end
it 'freezes upon access' do
expect(subject.value).to be_frozen
end
end
end
context 'freeze after calling #value' do
before do
subject.value
subject.freeze
end
context 'object' do
it 'returns value' do
expect(subject.value).to equal(value_arg)
end
it 'freezes value' do
expect(subject.value).to be_frozen
end
end
context 'proc' do
call_count = 0
let(:value_arg) do
proc do
call_count += 1
'Hello proc'
end
end
before do
call_count = 0
subject.freeze
end
it 'does not call the proc immediately' do
expect(call_count).to eql(0)
end
it 'returns proc return value' do
expect(subject.value).to eq('Hello proc')
end
it 'freezes upon access' do
expect(subject.value).to be_frozen
end
end
end
end
end
nanoc-4.11.0/nanoc/spec/nanoc/base/entities/outdatedness_status_spec.rb000066400000000000000000000055111340050175000262200ustar00rootroot00000000000000# frozen_string_literal: true
describe Nanoc::Int::OutdatednessStatus do
let(:status) { described_class.new }
describe '#reasons' do
subject { status.reasons }
context 'default' do
it { is_expected.to eql([]) }
end
context 'one passed in' do
let(:reasons) do
[
Nanoc::Int::OutdatednessReasons::CodeSnippetsModified,
]
end
let(:status) { described_class.new(reasons: reasons) }
it { is_expected.to eql(reasons) }
end
context 'two passed in' do
let(:reasons) do
[
Nanoc::Int::OutdatednessReasons::CodeSnippetsModified,
Nanoc::Int::OutdatednessReasons::ContentModified,
]
end
let(:status) { described_class.new(reasons: reasons) }
it { is_expected.to eql(reasons) }
end
end
describe '#props' do
subject { status.props.active }
context 'default' do
it { is_expected.to eql(Set.new) }
end
context 'specific one passed in' do
let(:props) do
Nanoc::Int::Props.new(attributes: true)
end
let(:status) { described_class.new(props: props) }
it { is_expected.to eql(Set.new([:attributes])) }
end
end
describe '#useful_to_apply' do
subject { status.useful_to_apply?(rule) }
let(:status) { described_class.new(props: props) }
let(:props) { Nanoc::Int::Props.new }
let(:rule) { Nanoc::Int::OutdatednessRules::RulesModified }
context 'no props' do
it { is_expected.to be }
end
context 'some props' do
context 'same props' do
let(:props) { Nanoc::Int::Props.new(compiled_content: true, path: true) }
it { is_expected.not_to be }
end
context 'different props' do
let(:props) { Nanoc::Int::Props.new(attributes: true) }
it { is_expected.to be }
end
end
context 'all props' do
let(:props) { Nanoc::Int::Props.new(raw_content: true, attributes: true, compiled_content: true, path: true) }
it { is_expected.not_to be }
end
end
describe '#update' do
subject { status.update(reason) }
let(:reason) { Nanoc::Int::OutdatednessReasons::ContentModified }
context 'no existing reason or props' do
it 'adds a reason' do
expect(subject.reasons).to eql([reason])
end
end
context 'existing reason' do
let(:status) { described_class.new(reasons: [old_reason]) }
let(:old_reason) { Nanoc::Int::OutdatednessReasons::NotWritten }
it 'adds a reason' do
expect(subject.reasons).to eql([old_reason, reason])
end
end
context 'existing props' do
let(:status) { described_class.new(props: Nanoc::Int::Props.new(attributes: true)) }
it 'updates props' do
expect(subject.props.active).to eql(Set.new(%i[raw_content attributes compiled_content]))
end
end
end
end
nanoc-4.11.0/nanoc/spec/nanoc/base/entities/pattern_spec.rb000066400000000000000000000073541340050175000235770ustar00rootroot00000000000000# frozen_string_literal: true
describe Nanoc::Int::Pattern do
describe '.from' do
it 'converts from string' do
pattern = described_class.from('/foo/x[ab]z/bar.*')
expect(pattern.match?('/foo/xaz/bar.html')).to eql(true)
expect(pattern.match?('/foo/xyz/bar.html')).to eql(false)
end
it 'converts from regex' do
pattern = described_class.from(%r{\A/foo/x[ab]z/bar\..*\z})
expect(pattern.match?('/foo/xaz/bar.html')).to eql(true)
expect(pattern.match?('/foo/xyz/bar.html')).to eql(false)
end
it 'converts from pattern' do
pattern = described_class.from('/foo/x[ab]z/bar.*')
pattern = described_class.from(pattern)
expect(pattern.match?('/foo/xaz/bar.html')).to eql(true)
expect(pattern.match?('/foo/xyz/bar.html')).to eql(false)
end
it 'converts from symbol' do
pattern = described_class.from(:'/foo/x[ab]z/bar.*')
expect(pattern.match?('/foo/xaz/bar.html')).to eql(true)
expect(pattern.match?('/foo/xyz/bar.html')).to eql(false)
end
it 'errors on other inputs' do
expect { described_class.from(123) }.to raise_error(ArgumentError)
end
it 'errors with a proper error message on other inputs' do
expect { described_class.from(nil) }
.to raise_error(ArgumentError, 'Do not know how to convert `nil` into a Nanoc::Pattern')
end
end
describe '#initialize' do
it 'errors' do
expect { described_class.new('/stuff') }
.to raise_error(NotImplementedError)
end
end
describe '#match?' do
it 'errors' do
expect { described_class.allocate.match?('/foo.md') }
.to raise_error(NotImplementedError)
end
end
describe '#captures' do
it 'errors' do
expect { described_class.allocate.captures('/foo.md') }
.to raise_error(NotImplementedError)
end
end
end
describe Nanoc::Int::RegexpPattern do
let(:pattern) { described_class.new(/the answer is (\d+)/) }
describe '#match?' do
it 'matches' do
expect(pattern.match?('the answer is 42')).to eql(true)
expect(pattern.match?('the answer is donkey')).to eql(false)
end
end
describe '#captures' do
it 'returns nil if it does not match' do
expect(pattern.captures('the answer is donkey')).to be_nil
end
it 'returns array if it matches' do
expect(pattern.captures('the answer is 42')).to eql(['42'])
end
end
describe '#to_s' do
subject { pattern.to_s }
it 'returns the regex' do
expect(subject).to eq('(?-mix:the answer is (\d+))')
end
end
end
describe Nanoc::Int::StringPattern do
describe '#match?' do
it 'matches simple strings' do
pattern = described_class.new('d*key')
expect(pattern.match?('donkey')).to eql(true)
expect(pattern.match?('giraffe')).to eql(false)
end
it 'matches with pathname option' do
pattern = described_class.new('/foo/*/bar/**/*.animal')
expect(pattern.match?('/foo/x/bar/a/b/donkey.animal')).to eql(true)
expect(pattern.match?('/foo/x/bar/donkey.animal')).to eql(true)
expect(pattern.match?('/foo/x/railroad/donkey.animal')).to eql(false)
end
it 'matches with extglob option' do
pattern = described_class.new('{b,gl}oat')
expect(pattern.match?('boat')).to eql(true)
expect(pattern.match?('gloat')).to eql(true)
expect(pattern.match?('stoat')).to eql(false)
end
end
describe '#captures' do
it 'returns nil' do
pattern = described_class.new('d*key')
expect(pattern.captures('donkey')).to be_nil
end
end
describe '#to_s' do
let(:pattern) { described_class.new('/foo/*/bar/**/*.animal') }
subject { pattern.to_s }
it 'returns the regex' do
expect(subject).to eq('/foo/*/bar/**/*.animal')
end
end
end
nanoc-4.11.0/nanoc/spec/nanoc/base/entities/processing_action_spec.rb000066400000000000000000000005251340050175000256240ustar00rootroot00000000000000# frozen_string_literal: true
describe Nanoc::Int::ProcessingAction do
let(:action) { described_class.new }
it 'is abstract' do
expect { action.serialize }.to raise_error(NotImplementedError)
expect { action.to_s }.to raise_error(NotImplementedError)
expect { action.inspect }.to raise_error(NotImplementedError)
end
end
nanoc-4.11.0/nanoc/spec/nanoc/base/entities/processing_actions/000077500000000000000000000000001340050175000244465ustar00rootroot00000000000000nanoc-4.11.0/nanoc/spec/nanoc/base/entities/processing_actions/filter_spec.rb000066400000000000000000000057731340050175000273060ustar00rootroot00000000000000# frozen_string_literal: true
describe Nanoc::Int::ProcessingActions::Filter do
let(:action) { described_class.new(:foo, awesome: true) }
describe '#serialize' do
subject { action.serialize }
it { is_expected.to eql([:filter, :foo, 'sJYzLjHGo1e4ytuDfnOLkqrt9QE=']) }
end
describe '#to_s' do
subject { action.to_s }
it { is_expected.to eql('filter :foo, {:awesome=>true}') }
end
describe '#inspect' do
subject { action.inspect }
it { is_expected.to eql('') }
end
describe '#== and #eql?' do
context 'other action is equal' do
let(:action_a) { described_class.new(:erb, foo: :bar) }
let(:action_b) { described_class.new(:erb, foo: :bar) }
it 'is ==' do
expect(action_a).to eq(action_b)
end
it 'is eql?' do
expect(action_a).to eql(action_b)
end
end
context 'other action has different name' do
let(:action_a) { described_class.new(:erb, foo: :bar) }
let(:action_b) { described_class.new(:haml, foo: :bar) }
it 'is not ==' do
expect(action_a).not_to eq(action_b)
end
it 'is not eql?' do
expect(action_a).not_to eql(action_b)
end
end
context 'other action has different params' do
let(:action_a) { described_class.new(:erb, foo: :bar) }
let(:action_b) { described_class.new(:erb, foo: :oink) }
it 'is not ==' do
expect(action_a).not_to eq(action_b)
end
it 'is not eql?' do
expect(action_a).not_to eql(action_b)
end
end
context 'other action is not a layout action' do
let(:action_a) { described_class.new(:erb, foo: :bar) }
let(:action_b) { :donkey }
it 'is not ==' do
expect(action_a).not_to eq(action_b)
end
it 'is not eql?' do
expect(action_a).not_to eql(action_b)
end
end
end
describe '#hash' do
context 'other action is equal' do
let(:action_a) { described_class.new(:erb, foo: :bar) }
let(:action_b) { described_class.new(:erb, foo: :bar) }
it 'is the same' do
expect(action_a.hash == action_b.hash).to eql(true)
end
end
context 'other action has different name' do
let(:action_a) { described_class.new(:erb, foo: :bar) }
let(:action_b) { described_class.new(:haml, foo: :bar) }
it 'is the same' do
expect(action_a.hash == action_b.hash).to eql(false)
end
end
context 'other action has different params' do
let(:action_a) { described_class.new(:erb, foo: :bar) }
let(:action_b) { described_class.new(:erb, foo: :oink) }
it 'is the same' do
expect(action_a.hash == action_b.hash).to eql(false)
end
end
context 'other action is not a layout action' do
let(:action_a) { described_class.new(:erb, foo: :bar) }
let(:action_b) { :woof }
it 'is the same' do
expect(action_a.hash == action_b.hash).to eql(false)
end
end
end
end
�����nanoc-4.11.0/nanoc/spec/nanoc/base/entities/processing_actions/layout_spec.rb�����������������������0000664�0000000�0000000�00000006161�13400501750�0027326�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������# frozen_string_literal: true
describe Nanoc::Int::ProcessingActions::Layout do
let(:action) { described_class.new('/foo.erb', awesome: true) }
describe '#serialize' do
subject { action.serialize }
it { is_expected.to eql([:layout, '/foo.erb', 'sJYzLjHGo1e4ytuDfnOLkqrt9QE=']) }
end
describe '#to_s' do
subject { action.to_s }
it { is_expected.to eql('layout " foo.erb",="" {:awesome="">true}') }
end
describe '#inspect' do
subject { action.inspect }
it { is_expected.to eql('') }
end
describe '#== and #eql?' do
context 'other action is equal' do
let(:action_a) { described_class.new('/foo.erb', foo: :bar) }
let(:action_b) { described_class.new('/foo.erb', foo: :bar) }
it 'is ==' do
expect(action_a).to eq(action_b)
end
it 'is eql?' do
expect(action_a).to eql(action_b)
end
end
context 'other action has different identifier' do
let(:action_a) { described_class.new('/foo.erb', foo: :bar) }
let(:action_b) { described_class.new('/bar.erb', foo: :bar) }
it 'is not ==' do
expect(action_a).not_to eq(action_b)
end
it 'is not eql?' do
expect(action_a).not_to eql(action_b)
end
end
context 'other action has different params' do
let(:action_a) { described_class.new('/foo.erb', foo: :bar) }
let(:action_b) { described_class.new('/foo.erb', foo: :oink) }
it 'is not ==' do
expect(action_a).not_to eq(action_b)
end
it 'is not eql?' do
expect(action_a).not_to eql(action_b)
end
end
context 'other action is not a layout action' do
let(:action_a) { described_class.new('/foo.erb', foo: :bar) }
let(:action_b) { :donkey }
it 'is not ==' do
expect(action_a).not_to eq(action_b)
end
it 'is not eql?' do
expect(action_a).not_to eql(action_b)
end
end
end
describe '#hash' do
context 'other action is equal' do
let(:action_a) { described_class.new('/foo.erb', foo: :bar) }
let(:action_b) { described_class.new('/foo.erb', foo: :bar) }
it 'is the same' do
expect(action_a.hash == action_b.hash).to eql(true)
end
end
context 'other action has different identifier' do
let(:action_a) { described_class.new('/foo.erb', foo: :bar) }
let(:action_b) { described_class.new('/bar.erb', foo: :bar) }
it 'is the same' do
expect(action_a.hash == action_b.hash).to eql(false)
end
end
context 'other action has different params' do
let(:action_a) { described_class.new('/foo.erb', foo: :bar) }
let(:action_b) { described_class.new('/foo.erb', foo: :oink) }
it 'is the same' do
expect(action_a.hash == action_b.hash).to eql(false)
end
end
context 'other action is not a layout action' do
let(:action_a) { described_class.new('/foo.erb', foo: :bar) }
let(:action_b) { :woof }
it 'is the same' do
expect(action_a.hash == action_b.hash).to eql(false)
end
end
end
end
���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������nanoc-4.11.0/nanoc/spec/nanoc/base/entities/processing_actions/snapshot_spec.rb���������������������0000664�0000000�0000000�00000007460�13400501750�0027653�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������# frozen_string_literal: true
describe Nanoc::Int::ProcessingActions::Snapshot do
let(:action) { described_class.new([:before_layout], ['/foo.md']) }
describe '#serialize' do
subject { action.serialize }
it { is_expected.to eql([:snapshot, [:before_layout], true, ['/foo.md']]) }
end
describe '#to_s' do
subject { action.to_s }
it { is_expected.to eql('snapshot [:before_layout], paths: [" foo.md"]')="" }="" end="" describe="" '#inspect'="" do="" subject="" {="" action.inspect="" it="" is_expected.to="" eql('') }
end
describe '#update' do
context 'with nothing' do
subject { action.update }
its(:snapshot_names) { is_expected.to eql([:before_layout]) }
its(:paths) { is_expected.to eql(['/foo.md']) }
end
context 'with snapshot name' do
subject { action.update(snapshot_names: [:zebra]) }
its(:snapshot_names) { is_expected.to eql(%i[before_layout zebra]) }
its(:paths) { is_expected.to eql(['/foo.md']) }
end
context 'with paths' do
subject { action.update(paths: ['/donkey.md', '/giraffe.md']) }
its(:snapshot_names) { is_expected.to eql([:before_layout]) }
its(:paths) { is_expected.to eql(['/foo.md', '/donkey.md', '/giraffe.md']) }
end
end
describe '#== and #eql?' do
context 'other action is equal' do
let(:action_a) { described_class.new([:erb], ['/foo.html']) }
let(:action_b) { described_class.new([:erb], ['/foo.html']) }
it 'is ==' do
expect(action_a).to eq(action_b)
end
it 'is eql?' do
expect(action_a).to eql(action_b)
end
end
context 'other action has different name' do
let(:action_a) { described_class.new([:erb], ['/foo.html']) }
let(:action_b) { described_class.new([:haml], ['/foo.html']) }
it 'is not ==' do
expect(action_a).not_to eq(action_b)
end
it 'is not eql?' do
expect(action_a).not_to eql(action_b)
end
end
context 'other action has different paths' do
let(:action_a) { described_class.new([:erb], ['/foo.html']) }
let(:action_b) { described_class.new([:erb], ['/foo.htm']) }
it 'is not ==' do
expect(action_a).not_to eq(action_b)
end
it 'is not eql?' do
expect(action_a).not_to eql(action_b)
end
end
context 'other action is not a layout action' do
let(:action_a) { described_class.new([:erb], ['/foo.html']) }
let(:action_b) { :donkey }
it 'is not ==' do
expect(action_a).not_to eq(action_b)
end
it 'is not eql?' do
expect(action_a).not_to eql(action_b)
end
end
end
describe '#hash' do
context 'other action is equal' do
let(:action_a) { described_class.new([:erb], ['/foo.html']) }
let(:action_b) { described_class.new([:erb], ['/foo.html']) }
it 'is the same' do
expect(action_a.hash == action_b.hash).to eql(true)
end
end
context 'other action has different name' do
let(:action_a) { described_class.new([:erb], ['/foo.html']) }
let(:action_b) { described_class.new([:haml], ['/foo.html']) }
it 'is the same' do
expect(action_a.hash == action_b.hash).to eql(false)
end
end
context 'other action has different paths' do
let(:action_a) { described_class.new([:erb], ['/foo.html']) }
let(:action_b) { described_class.new([:erb], ['/foo.htm']) }
it 'is the same' do
expect(action_a.hash == action_b.hash).to eql(false)
end
end
context 'other action is not a layout action' do
let(:action_a) { described_class.new([:erb], ['/foo.html']) }
let(:action_b) { :woof }
it 'is the same' do
expect(action_a.hash == action_b.hash).to eql(false)
end
end
end
end
nanoc-4.11.0/nanoc/spec/nanoc/base/entities/props_spec.rb000066400000000000000000000275041340050175000232640ustar00rootroot00000000000000# frozen_string_literal: true
describe Nanoc::Int::Props do
let(:props) { described_class.new }
let(:props_all) do
described_class.new(raw_content: true, attributes: true, compiled_content: true, path: true)
end
describe '#inspect' do
subject { props.inspect }
context 'nothing active' do
it { is_expected.to eql('Props(____)') }
end
context 'attributes active' do
let(:props) { described_class.new(attributes: true) }
it { is_expected.to eql('Props(_a__)') }
end
context 'attributes and compiled_content active' do
let(:props) { described_class.new(attributes: true, compiled_content: true) }
it { is_expected.to eql('Props(_ac_)') }
end
context 'compiled_content active' do
let(:props) { described_class.new(compiled_content: true) }
it { is_expected.to eql('Props(__c_)') }
end
end
describe '#to_s' do
subject { props.to_s }
context 'nothing active' do
it { is_expected.to eql('____') }
end
context 'attributes active' do
let(:props) { described_class.new(attributes: true) }
it { is_expected.to eql('_a__') }
end
context 'attributes and compiled_content active' do
let(:props) { described_class.new(attributes: true, compiled_content: true) }
it { is_expected.to eql('_ac_') }
end
context 'compiled_content active' do
let(:props) { described_class.new(compiled_content: true) }
it { is_expected.to eql('__c_') }
end
end
describe '#raw_content?' do
subject { props.raw_content? }
context 'nothing active' do
it { is_expected.not_to be }
end
context 'raw_content active' do
let(:props) { described_class.new(raw_content: true) }
it { is_expected.to be }
end
context 'raw_content and compiled_content active' do
let(:props) { described_class.new(raw_content: true, compiled_content: true) }
it { is_expected.to be }
end
context 'compiled_content active' do
let(:props) { described_class.new(compiled_content: true) }
it { is_expected.not_to be }
end
context 'all active' do
let(:props) { described_class.new(raw_content: true, attributes: true, compiled_content: true, path: true) }
it { is_expected.to be }
end
context 'raw_content is empty list' do
let(:props) { described_class.new(raw_content: []) }
it { is_expected.not_to be }
end
context 'raw_content is non-empty list' do
let(:props) { described_class.new(raw_content: ['/asdf.*']) }
it { is_expected.to be }
end
end
describe '#attributes?' do
subject { props.attributes? }
context 'nothing active' do
it { is_expected.not_to be }
end
context 'attributes active' do
let(:props) { described_class.new(attributes: true) }
it { is_expected.to be }
end
context 'attributes and compiled_content active' do
let(:props) { described_class.new(attributes: true, compiled_content: true) }
it { is_expected.to be }
end
context 'compiled_content active' do
let(:props) { described_class.new(compiled_content: true) }
it { is_expected.not_to be }
end
context 'all active' do
let(:props) { described_class.new(raw_content: true, attributes: true, compiled_content: true, path: true) }
it { is_expected.to be }
end
context 'attributes is empty list' do
let(:props) { described_class.new(attributes: []) }
it { is_expected.not_to be }
end
context 'attributes is non-empty list' do
let(:props) { described_class.new(attributes: [:donkey]) }
it { is_expected.to be }
end
end
describe '#compiled_content?' do
# …
end
describe '#path?' do
# …
end
describe '#merge' do
subject { props.merge(other_props).active }
context 'nothing + nothing' do
let(:props) { described_class.new }
let(:other_props) { described_class.new }
it { is_expected.to eql(Set.new) }
end
context 'nothing + some' do
let(:props) { described_class.new }
let(:other_props) { described_class.new(raw_content: true) }
it { is_expected.to eql(Set.new([:raw_content])) }
end
context 'nothing + all' do
let(:props) { described_class.new }
let(:other_props) { props_all }
it { is_expected.to eql(Set.new(%i[raw_content attributes compiled_content path])) }
end
context 'some + nothing' do
let(:props) { described_class.new(compiled_content: true) }
let(:other_props) { described_class.new }
it { is_expected.to eql(Set.new([:compiled_content])) }
end
context 'some + others' do
let(:props) { described_class.new(compiled_content: true) }
let(:other_props) { described_class.new(raw_content: true) }
it { is_expected.to eql(Set.new(%i[raw_content compiled_content])) }
end
context 'some + all' do
let(:props) { described_class.new(compiled_content: true) }
let(:other_props) { props_all }
it { is_expected.to eql(Set.new(%i[raw_content attributes compiled_content path])) }
end
context 'all + nothing' do
let(:props) { props_all }
let(:other_props) { described_class.new }
it { is_expected.to eql(Set.new(%i[raw_content attributes compiled_content path])) }
end
context 'some + all' do
let(:props) { props_all }
let(:other_props) { described_class.new(compiled_content: true) }
it { is_expected.to eql(Set.new(%i[raw_content attributes compiled_content path])) }
end
context 'all + all' do
let(:props) { props_all }
let(:other_props) { props_all }
it { is_expected.to eql(Set.new(%i[raw_content attributes compiled_content path])) }
end
end
describe '#merge_attributes' do
let(:props_attrs_true) do
described_class.new(attributes: true)
end
let(:props_attrs_false) do
described_class.new(attributes: false)
end
let(:props_attrs_list_a) do
described_class.new(attributes: %i[donkey giraffe])
end
let(:props_attrs_list_b) do
described_class.new(attributes: %i[giraffe zebra])
end
subject { props.merge(other_props).attributes }
context 'false + false' do
let(:props) { props_attrs_false }
let(:other_props) { props_attrs_false }
it { is_expected.to be(false) }
end
context 'false + true' do
let(:props) { props_attrs_false }
let(:other_props) { props_attrs_true }
it { is_expected.to be(true) }
end
context 'false + list' do
let(:props) { props_attrs_false }
let(:other_props) { props_attrs_list_a }
it { is_expected.to be_a(Set) }
it { is_expected.to match_array(%i[donkey giraffe]) }
end
context 'true + false' do
let(:props) { props_attrs_true }
let(:other_props) { props_attrs_false }
it { is_expected.to be(true) }
end
context 'true + true' do
let(:props) { props_attrs_true }
let(:other_props) { props_attrs_true }
it { is_expected.to be(true) }
end
context 'true + list' do
let(:props) { props_attrs_true }
let(:other_props) { props_attrs_list_a }
it { is_expected.to be(true) }
end
context 'list + false' do
let(:props) { props_attrs_list_a }
let(:other_props) { props_attrs_false }
it { is_expected.to be_a(Set) }
it { is_expected.to match_array(%i[donkey giraffe]) }
end
context 'list + true' do
let(:props) { props_attrs_list_a }
let(:other_props) { props_attrs_true }
it { is_expected.to be(true) }
end
context 'list + list' do
let(:props) { props_attrs_list_a }
let(:other_props) { props_attrs_list_b }
it { is_expected.to be_a(Set) }
it { is_expected.to match_array(%i[donkey giraffe zebra]) }
end
end
describe '#merge_raw_content' do
let(:props_raw_content_true) do
described_class.new(raw_content: true)
end
let(:props_raw_content_false) do
described_class.new(raw_content: false)
end
let(:props_raw_content_list_a) do
described_class.new(raw_content: %w[donkey giraffe])
end
let(:props_raw_content_list_b) do
described_class.new(raw_content: %w[giraffe zebra])
end
subject { props.merge(other_props).raw_content }
context 'false + false' do
let(:props) { props_raw_content_false }
let(:other_props) { props_raw_content_false }
it { is_expected.to be(false) }
end
context 'false + true' do
let(:props) { props_raw_content_false }
let(:other_props) { props_raw_content_true }
it { is_expected.to be(true) }
end
context 'false + list' do
let(:props) { props_raw_content_false }
let(:other_props) { props_raw_content_list_a }
it { is_expected.to be_a(Set) }
it { is_expected.to match_array(%w[donkey giraffe]) }
end
context 'true + false' do
let(:props) { props_raw_content_true }
let(:other_props) { props_raw_content_false }
it { is_expected.to be(true) }
end
context 'true + true' do
let(:props) { props_raw_content_true }
let(:other_props) { props_raw_content_true }
it { is_expected.to be(true) }
end
context 'true + list' do
let(:props) { props_raw_content_true }
let(:other_props) { props_raw_content_list_a }
it { is_expected.to be(true) }
end
context 'list + false' do
let(:props) { props_raw_content_list_a }
let(:other_props) { props_raw_content_false }
it { is_expected.to be_a(Set) }
it { is_expected.to match_array(%w[donkey giraffe]) }
end
context 'list + true' do
let(:props) { props_raw_content_list_a }
let(:other_props) { props_raw_content_true }
it { is_expected.to be(true) }
end
context 'list + list' do
let(:props) { props_raw_content_list_a }
let(:other_props) { props_raw_content_list_b }
it { is_expected.to be_a(Set) }
it { is_expected.to match_array(%w[donkey giraffe zebra]) }
end
end
describe '#active' do
subject { props.active }
context 'nothing active' do
let(:props) { described_class.new }
it { is_expected.to eql(Set.new) }
end
context 'raw_content active' do
let(:props) { described_class.new(raw_content: true) }
it { is_expected.to eql(Set.new([:raw_content])) }
end
context 'attributes active' do
let(:props) { described_class.new(attributes: true) }
it { is_expected.to eql(Set.new([:attributes])) }
end
context 'compiled_content active' do
let(:props) { described_class.new(compiled_content: true) }
it { is_expected.to eql(Set.new([:compiled_content])) }
end
context 'path active' do
let(:props) { described_class.new(path: true) }
it { is_expected.to eql(Set.new([:path])) }
end
context 'attributes and compiled_content active' do
let(:props) { described_class.new(attributes: true, compiled_content: true) }
it { is_expected.to eql(Set.new(%i[attributes compiled_content])) }
end
context 'all active' do
let(:props) { described_class.new(raw_content: true, attributes: true, compiled_content: true, path: true) }
it { is_expected.to eql(Set.new(%i[raw_content attributes compiled_content path])) }
end
end
describe '#to_h' do
subject { props.to_h }
context 'nothing' do
let(:props) { described_class.new }
it { is_expected.to eql(raw_content: false, attributes: false, compiled_content: false, path: false) }
end
context 'some' do
let(:props) { described_class.new(attributes: true, compiled_content: true) }
it { is_expected.to eql(raw_content: false, attributes: true, compiled_content: true, path: false) }
end
context 'all' do
let(:props) { props_all }
it { is_expected.to eql(raw_content: true, attributes: true, compiled_content: true, path: true) }
end
end
end
nanoc-4.11.0/nanoc/spec/nanoc/base/entities/site_spec.rb000066400000000000000000000034011340050175000230530ustar00rootroot00000000000000# frozen_string_literal: true
describe Nanoc::Int::Site do
describe '#freeze' do
let(:site) do
described_class.new(
config: config,
code_snippets: code_snippets,
data_source: Nanoc::Int::InMemDataSource.new(items, layouts),
)
end
let(:config) do
Nanoc::Int::Configuration.new(dir: Dir.getwd).with_defaults
end
let(:code_snippets) do
[
Nanoc::Int::CodeSnippet.new('FOO = 123', 'hello.rb'),
Nanoc::Int::CodeSnippet.new('BAR = 123', 'hi.rb'),
]
end
let(:items) do
Nanoc::Int::ItemCollection.new(
config,
[
Nanoc::Int::Item.new('foo', {}, '/foo.md'),
Nanoc::Int::Item.new('bar', {}, '/bar.md'),
],
)
end
let(:layouts) do
Nanoc::Int::LayoutCollection.new(
config,
[
Nanoc::Int::Layout.new('foo', {}, '/foo.md'),
Nanoc::Int::Layout.new('bar', {}, '/bar.md'),
],
)
end
before do
site.freeze
end
it 'freezes the configuration' do
expect(site.config).to be_frozen
end
it 'freezes the configuration contents' do
expect(site.config.output_dir).to be_frozen
end
it 'freezes items collection' do
expect(site.items).to be_frozen
end
it 'freezes individual items' do
expect(site.items).to all(be_frozen)
end
it 'freezes layouts collection' do
expect(site.layouts).to be_frozen
end
it 'freezes individual layouts' do
expect(site.layouts).to all(be_frozen)
end
it 'freezes code snippets collection' do
expect(site.code_snippets).to be_frozen
end
it 'freezes individual code snippets' do
expect(site.code_snippets).to all(be_frozen)
end
end
end
nanoc-4.11.0/nanoc/spec/nanoc/base/errors/000077500000000000000000000000001340050175000202425ustar00rootroot00000000000000nanoc-4.11.0/nanoc/spec/nanoc/base/errors/dependency_cycle_spec.rb000066400000000000000000000022171340050175000251000ustar00rootroot00000000000000# frozen_string_literal: true
describe Nanoc::Int::Errors::DependencyCycle do
subject(:error) { described_class.new(stack) }
let(:stack) do
[
rep_a,
rep_b,
rep_c,
rep_d,
rep_e,
rep_b,
]
end
let(:rep_a) { Nanoc::Int::ItemRep.new(Nanoc::Int::Item.new('a', {}, '/a.md'), :default) }
let(:rep_b) { Nanoc::Int::ItemRep.new(Nanoc::Int::Item.new('b', {}, '/b.md'), :default) }
let(:rep_c) { Nanoc::Int::ItemRep.new(Nanoc::Int::Item.new('c', {}, '/c.md'), :default) }
let(:rep_d) { Nanoc::Int::ItemRep.new(Nanoc::Int::Item.new('d', {}, '/d.md'), :default) }
let(:rep_e) { Nanoc::Int::ItemRep.new(Nanoc::Int::Item.new('e', {}, '/e.md'), :default) }
it 'has an informative error message' do
expected = <<~EOS
The site cannot be compiled because there is a dependency cycle:
(1) item /b.md, rep :default, uses compiled content of
(2) item /c.md, rep :default, uses compiled content of
(3) item /d.md, rep :default, uses compiled content of
(4) item /e.md, rep :default, uses compiled content of (1)
EOS
expect(error.message).to eql(expected)
end
end
nanoc-4.11.0/nanoc/spec/nanoc/base/feature_spec.rb000066400000000000000000000055051340050175000217250ustar00rootroot00000000000000# frozen_string_literal: true
describe Nanoc::Feature do
describe '.enabled?' do
subject { described_class.enabled?(feature_name) }
let(:feature_name) { 'magic' }
before do
Nanoc::Feature.reset_caches
ENV['NANOC_FEATURES'] = +''
end
context 'not set' do
it { is_expected.not_to be }
end
context 'set to list not including feature' do
before { ENV['NANOC_FEATURES'] = 'foo,bar' }
it { is_expected.not_to be }
end
context 'set to all' do
before { ENV['NANOC_FEATURES'] = 'all' }
it { is_expected.to be }
end
context 'set to list including feature' do
before { ENV['NANOC_FEATURES'] = 'foo,magic,bar' }
it { is_expected.to be }
end
end
describe '.enable' do
subject do
described_class.enable(feature_name) do
Nanoc::Feature.enabled?(feature_name)
end
end
let(:feature_name) { 'magic' }
before do
Nanoc::Feature.reset_caches
ENV['NANOC_FEATURES'] = +''
end
context 'not set' do
it { is_expected.to be }
it 'unsets afterwards' do
expect(Nanoc::Feature.enabled?(feature_name)).not_to be
end
end
context 'set to list not including feature' do
before { ENV['NANOC_FEATURES'] = 'foo,bar' }
it { is_expected.to be }
it 'unsets afterwards' do
expect(Nanoc::Feature.enabled?(feature_name)).not_to be
end
end
context 'set to all' do
before { ENV['NANOC_FEATURES'] = 'all' }
it { is_expected.to be }
end
context 'set to list including feature' do
before { ENV['NANOC_FEATURES'] = 'foo,magic,bar' }
it { is_expected.to be }
end
end
describe '.all_outdated' do
it 'refuses outdated features' do
# If this spec fails, there are features marked as experimental in the previous minor or major
# release, but not in the current one. Either remove the feature, or mark it as experimental
# in the current release.
expect(Nanoc::Feature.all_outdated).to be_empty
end
describe 'fake outdated features' do
before { Nanoc::Feature.define('abc', version: '4.2.x') }
after { Nanoc::Feature.undefine('abc') }
it 'detects outdated features' do
expect(Nanoc::Feature.all_outdated).to eq(['abc'])
end
end
end
describe '.define and .undefine' do
let(:feature_name) { 'testing123' }
after { Nanoc::Feature.undefine(feature_name) if defined?(Nanoc::Feature::TESTING123) }
it 'can define' do
Nanoc::Feature.define(feature_name, version: '4.3.x')
expect(Nanoc::Feature::TESTING123).not_to be_nil
end
it 'can undefine' do
Nanoc::Feature.define(feature_name, version: '4.3.x')
Nanoc::Feature.undefine(feature_name)
expect { Nanoc::Feature::TESTING123 }.to raise_error(NameError)
end
end
end
nanoc-4.11.0/nanoc/spec/nanoc/base/filter_spec.rb000066400000000000000000000163041340050175000215560ustar00rootroot00000000000000# frozen_string_literal: true
describe Nanoc::Filter do
describe '.define' do
context 'simple filter' do
let(:filter_name) { :b5355bbb4d772b9853d21be57da614dba521dbbb }
let(:filter_class) { Nanoc::Filter.named(filter_name) }
before do
Nanoc::Filter.define(filter_name) do |content, _params|
content.upcase
end
end
it 'defines a filter' do
expect(filter_class).not_to be_nil
end
it 'defines a callable filter' do
expect(filter_class.new.run('foo', {})).to eql('FOO')
end
end
context 'filter that accesses assigns' do
let(:filter_name) { :d7ed105d460e99a3d38f46af023d9490c140fdd9 }
let(:filter_class) { Nanoc::Filter.named(filter_name) }
let(:filter) { filter_class.new(assigns) }
let(:assigns) { { animal: 'Giraffe' } }
before do
Nanoc::Filter.define(filter_name) do |_content, _params|
@animal
end
end
it 'can access assigns' do
expect(filter.setup_and_run(:__irrelevant__, {})).to eq('Giraffe')
end
end
end
describe '.named!' do
it 'returns filter if exists' do
expect(Nanoc::Filter.named!(:erb)).not_to be_nil
expect(Nanoc::Filter.named!(:erb).identifier).to eq(:erb)
end
it 'raises if non-existent' do
expect { Nanoc::Filter.named!(:ajklsdfklasjflkd) }
.to raise_error(
Nanoc::Int::Errors::UnknownFilter,
'The requested filter, “ajklsdfklasjflkd”, does not exist.',
)
end
end
describe 'assigns' do
context 'no assigns given' do
subject { described_class.new }
it 'has empty assigns' do
expect(subject.instance_eval { @assigns }).to eq({})
end
end
context 'assigns given' do
subject { described_class.new(foo: 'bar') }
it 'has assigns' do
expect(subject.instance_eval { @assigns }).to eq(foo: 'bar')
end
it 'can access assigns with @' do
expect(subject.instance_eval { @foo }).to eq('bar')
end
it 'can access assigns without @' do
expect(subject.instance_eval { foo }).to eq('bar')
end
end
end
describe '#run' do
context 'no subclass' do
subject { described_class.new.run('stuff') }
it 'errors' do
expect { subject }.to raise_error(NotImplementedError)
end
end
context 'subclass' do
# TODO
end
end
describe '#filename' do
subject { described_class.new(assigns).filename }
context 'assigns contains item + item rep' do
let(:item) { Nanoc::Int::Item.new('asdf', {}, '/donkey.md') }
let(:item_rep) { Nanoc::Int::ItemRep.new(item, :animal) }
let(:assigns) { { item: item, item_rep: item_rep } }
it { is_expected.to eq('item /donkey.md (rep animal)') }
end
context 'assigns contains layout' do
let(:layout) { Nanoc::Int::Layout.new('asdf', {}, '/donkey.md') }
let(:assigns) { { layout: layout } }
it { is_expected.to eq('layout /donkey.md') }
end
context 'assigns contains neither' do
let(:assigns) { {} }
it { is_expected.to eq('?') }
end
end
describe '.always_outdated? + .always_outdated' do
context 'not always outdated' do
let(:filter_class) do
Class.new(Nanoc::Filter) do
identifier :bea22a356b6b031cea1e615087179803818c6a53
def run(content, _params)
content.upcase
end
end
end
it 'is not always outdated' do
expect(filter_class).not_to be_always_outdated
end
end
context 'always outdated' do
let(:filter_class) do
Class.new(Nanoc::Filter) do
identifier :d7413fa71223e5e69b03a0abfa25806e07e14f3a
always_outdated
def run(content, _params)
content.upcase
end
end
end
it 'is always outdated' do
expect(filter_class).to be_always_outdated
end
end
end
describe '#depend_on' do
subject { filter.depend_on(item_views) }
let(:filter) { Nanoc::Filters::ERB.new(assigns) }
let(:item_views) { [item_view] }
let(:item) { Nanoc::Int::Item.new('foo', {}, '/stuff.md') }
let(:item_view) { Nanoc::CompilationItemView.new(item, view_context) }
let(:rep) { Nanoc::Int::ItemRep.new(item, :default) }
let(:view_context) do
Nanoc::ViewContextForCompilation.new(
reps: reps,
items: Nanoc::Int::ItemCollection.new(config),
dependency_tracker: dependency_tracker,
compilation_context: double(:compilation_context),
snapshot_repo: double(:snapshot_repo),
)
end
let(:dependency_tracker) { Nanoc::Int::DependencyTracker.new(dependency_store) }
let(:dependency_store) { Nanoc::Int::DependencyStore.new(empty_items, empty_layouts, config) }
let(:empty_items) { Nanoc::Int::ItemCollection.new(config) }
let(:empty_layouts) { Nanoc::Int::LayoutCollection.new(config) }
let(:config) { Nanoc::Int::Configuration.new(dir: Dir.getwd).with_defaults }
let(:reps) { Nanoc::Int::ItemRepRepo.new }
let(:assigns) do
{
item: item_view,
}
end
context 'reps exist' do
before { reps << rep }
context 'rep is compiled' do
before do
rep.compiled = true
end
example do
expect { subject }.not_to yield_from_fiber(an_instance_of(Nanoc::Int::Errors::UnmetDependency))
end
it 'creates dependency' do
expect { subject }
.to create_dependency_on(item_view)
end
end
context 'rep is not compiled' do
example do
fiber = Fiber.new { subject }
# resume 1
res = fiber.resume
expect(res).to be_a(Nanoc::Int::Errors::UnmetDependency)
expect(res.rep).to eql(rep)
# resume 2
expect(fiber.resume).not_to be_a(Nanoc::Int::Errors::UnmetDependency)
end
end
context 'multiple reps exist' do
let(:other_rep) { Nanoc::Int::ItemRep.new(item, :default) }
before do
reps << other_rep
rep.compiled = false
other_rep.compiled = false
end
it 'yields an unmet dependency error twice' do
fiber = Fiber.new { subject }
# resume 1
res = fiber.resume
expect(res).to be_a(Nanoc::Int::Errors::UnmetDependency)
expect(res.rep).to eql(rep)
# resume 2
res = fiber.resume
expect(res).to be_a(Nanoc::Int::Errors::UnmetDependency)
expect(res.rep).to eql(other_rep)
# resume 3
expect(fiber.resume).not_to be_a(Nanoc::Int::Errors::UnmetDependency)
end
end
end
context 'no reps exist' do
context 'textual' do
it 'creates dependency' do
expect { subject }
.to create_dependency_on(item_view)
end
end
context 'binary' do
let(:item) { Nanoc::Int::Item.new(content, {}, '/stuff.md') }
let(:filename) { File.expand_path('foo.dat') }
let(:content) { Nanoc::Int::BinaryContent.new(filename) }
it 'creates dependency' do
expect { subject }
.to create_dependency_on(item_view)
end
end
end
end
end
nanoc-4.11.0/nanoc/spec/nanoc/base/item_rep_writer_spec.rb000066400000000000000000000103551340050175000234710ustar00rootroot00000000000000# frozen_string_literal: true
describe Nanoc::Int::ItemRepWriter do
describe '#write' do
let(:raw_path) { Dir.getwd + '/output/blah.dat' }
let(:item) { Nanoc::Int::Item.new(orig_content, {}, '/foo') }
let(:item_rep) do
Nanoc::Int::ItemRep.new(item, :default).tap do |ir|
ir.raw_paths = raw_paths
end
end
let(:snapshot_contents) do
{
last: Nanoc::Int::TextualContent.new('last content'),
donkey: Nanoc::Int::TextualContent.new('donkey content'),
}
end
let(:snapshot_name) { :donkey }
let(:raw_paths) do
{ snapshot_name => [raw_path] }
end
let(:snapshot_repo) { Nanoc::Int::SnapshotRepo.new }
let(:written_paths) { [] }
subject { described_class.new.write(item_rep, snapshot_repo, snapshot_name, written_paths) }
before do
expect(File.directory?('output')).to be_falsy
snapshot_contents.each_pair do |key, value|
snapshot_repo.set(item_rep, key, value)
end
end
context 'binary item rep' do
let(:orig_content) { Nanoc::Int::BinaryContent.new(File.expand_path('foo.dat')) }
let(:snapshot_contents) do
{
last: Nanoc::Int::BinaryContent.new(File.expand_path('input-last.dat')),
donkey: Nanoc::Int::BinaryContent.new(File.expand_path('input-donkey.dat')),
}
end
before do
File.write(snapshot_contents[:last].filename, 'binary last stuff')
File.write(snapshot_contents[:donkey].filename, 'binary donkey stuff')
end
it 'copies contents' do
expect(Nanoc::Int::NotificationCenter).to receive(:post)
.with(:rep_write_started, item_rep, Dir.getwd + '/output/blah.dat')
expect(Nanoc::Int::NotificationCenter).to receive(:post)
.with(:rep_write_ended, item_rep, true, Dir.getwd + '/output/blah.dat', true, true)
subject
expect(File.read('output/blah.dat')).to eql('binary donkey stuff')
end
it 'uses hard links' do
subject
input = File.stat(snapshot_contents[:donkey].filename)
output = File.stat('output/blah.dat')
expect(input.ino).to eq(output.ino)
end
context 'output file already exists' do
let(:old_mtime) { Time.at((Time.now - 600).to_i) }
before do
FileUtils.mkdir_p('output')
File.write('output/blah.dat', old_content)
FileUtils.touch('output/blah.dat', mtime: old_mtime)
end
context 'file is identical' do
let(:old_content) { 'binary donkey stuff' }
it 'keeps mtime' do
subject
expect(File.mtime('output/blah.dat')).to eql(old_mtime)
end
end
context 'file is not identical' do
let(:old_content) { 'other binary donkey stuff' }
it 'updates mtime' do
subject
expect(File.mtime('output/blah.dat')).to be > (Time.now - 1)
end
end
end
end
context 'textual item rep' do
let(:orig_content) { Nanoc::Int::TextualContent.new('Hallo Welt') }
it 'writes' do
expect(Nanoc::Int::NotificationCenter).to receive(:post)
.with(:rep_write_started, item_rep, Dir.getwd + '/output/blah.dat')
expect(Nanoc::Int::NotificationCenter).to receive(:post)
.with(:rep_write_ended, item_rep, false, Dir.getwd + '/output/blah.dat', true, true)
subject
expect(File.read('output/blah.dat')).to eql('donkey content')
end
context 'output file already exists' do
let(:old_mtime) { Time.at((Time.now - 600).to_i) }
before do
FileUtils.mkdir_p('output')
File.write('output/blah.dat', old_content)
FileUtils.touch('output/blah.dat', mtime: old_mtime)
end
context 'file is identical' do
let(:old_content) { 'donkey content' }
it 'keeps mtime' do
subject
expect(File.mtime('output/blah.dat')).to eql(old_mtime)
end
end
context 'file is not identical' do
let(:old_content) { 'other donkey content' }
it 'updates mtime' do
subject
expect(File.mtime('output/blah.dat')).to be > (Time.now - 1)
end
end
end
end
end
end
nanoc-4.11.0/nanoc/spec/nanoc/base/repos/000077500000000000000000000000001340050175000200565ustar00rootroot00000000000000nanoc-4.11.0/nanoc/spec/nanoc/base/repos/aggregate_data_source_spec.rb000066400000000000000000000035011340050175000257130ustar00rootroot00000000000000# frozen_string_literal: true
describe Nanoc::Int::AggregateDataSource, stdio: true do
let(:klass_1) do
Class.new(Nanoc::DataSource) do
def items
[Nanoc::Int::Item.new('One', {}, '/one.md')]
end
def item_changes
%i[one_foo one_bar]
end
def layouts
[Nanoc::Int::Layout.new('One', {}, '/one.md')]
end
def layout_changes
%i[one_foo one_bar]
end
end
end
let(:klass_2) do
Class.new(Nanoc::DataSource) do
def items
[Nanoc::Int::Item.new('Two', {}, '/two.md')]
end
def item_changes
%i[two_foo two_bar]
end
def layouts
[Nanoc::Int::Layout.new('Two', {}, '/two.md')]
end
def layout_changes
%i[two_foo two_bar]
end
end
end
let(:data_source_1) do
klass_1.new({}, nil, nil, {})
end
let(:data_source_2) do
klass_2.new({}, nil, nil, {})
end
subject(:data_source) do
described_class.new([data_source_1, data_source_2], {})
end
describe '#items' do
subject { data_source.items }
it 'contains all items' do
expect(subject).to match_array(data_source_1.items + data_source_2.items)
end
end
describe '#layouts' do
subject { data_source.layouts }
it 'contains all layouts' do
expect(subject).to match_array(data_source_1.layouts + data_source_2.layouts)
end
end
describe '#item_changes' do
subject { data_source.item_changes }
it 'yields changes from both' do
expect(subject).to match_array(data_source_1.item_changes + data_source_2.item_changes)
end
end
describe '#layout_changes' do
subject { data_source.layout_changes }
it 'yields changes from both' do
expect(subject).to match_array(data_source_1.layout_changes + data_source_2.layout_changes)
end
end
end
nanoc-4.11.0/nanoc/spec/nanoc/base/repos/checksum_store_spec.rb000066400000000000000000000076141340050175000244430ustar00rootroot00000000000000# frozen_string_literal: true
describe Nanoc::Int::ChecksumStore do
let(:store) { described_class.new(config: config, objects: objects) }
let(:config) { Nanoc::Int::Configuration.new(dir: Dir.getwd).with_defaults }
let(:objects) { [item, code_snippet] }
let(:item) { Nanoc::Int::Item.new('asdf', item_attributes, '/foo.md') }
let(:other_item) { Nanoc::Int::Item.new('asdf', other_item_attributes, '/sneaky.md') }
let(:item_attributes) { {} }
let(:other_item_attributes) { {} }
let(:code_snippet) { Nanoc::Int::CodeSnippet.new('def hi ; end', 'lib/foo.rb') }
let(:other_code_snippet) { Nanoc::Int::CodeSnippet.new('def ho ; end', 'lib/bar.rb') }
context 'nothing added' do
it 'has no checksum' do
expect(store[item]).to be_nil
end
it 'has no content checksum' do
expect(store.content_checksum_for(item)).to be_nil
end
it 'has no attributes checksum' do
expect(store.attributes_checksum_for(item)).to be_nil
end
end
context 'setting content on known non-document' do
before { store.add(code_snippet) }
it 'has checksum' do
expect(store[code_snippet]).not_to be_nil
end
it 'has no content checksum' do
expect(store.content_checksum_for(code_snippet)).to be_nil
end
it 'has no attributes checksum' do
expect(store.attributes_checksum_for(code_snippet)).to be_nil
end
context 'after storing and loading' do
before do
store.store
store.load
end
it 'has checksum' do
expect(store[code_snippet]).not_to be_nil
end
end
end
context 'setting content on unknown non-document' do
before { store.add(other_code_snippet) }
it 'has checksum' do
expect(store[other_code_snippet]).not_to be_nil
end
it 'has no content checksum' do
expect(store.content_checksum_for(other_code_snippet)).to be_nil
end
it 'has no attributes checksum' do
expect(store.attributes_checksum_for(other_code_snippet)).to be_nil
end
context 'after storing and loading' do
before do
store.store
store.load
end
it 'has no checksum' do
expect(store[other_code_snippet]).to be_nil
end
end
end
context 'setting content on known item' do
before { store.add(item) }
it 'has checksum' do
expect(store[item]).not_to be_nil
end
it 'has content checksum' do
expect(store.content_checksum_for(item)).not_to be_nil
end
it 'has attributes checksum' do
expect(store.attributes_checksum_for(item)).not_to be_nil
expect(store.attributes_checksum_for(item)).to eq({})
end
context 'item has attributes' do
let(:item_attributes) { { animal: 'donkey' } }
it 'has attribute checksum for specified attribute' do
expect(store.attributes_checksum_for(item)).to have_key(:animal)
end
end
context 'after storing and loading' do
before do
store.store
store.load
end
it 'has checksum' do
expect(store[item]).not_to be_nil
end
end
end
context 'setting content on unknown item' do
before { store.add(other_item) }
it 'has checksum' do
expect(store[other_item]).not_to be_nil
end
it 'has content checksum' do
expect(store.content_checksum_for(other_item)).not_to be_nil
end
it 'has attributes checksum' do
expect(store.attributes_checksum_for(other_item)).not_to be_nil
end
context 'item has attributes' do
let(:other_item_attributes) { { location: 'Bernauer Str.' } }
it 'has attribute checksum for specified attribute' do
expect(store.attributes_checksum_for(other_item)).to have_key(:location)
end
end
context 'after storing and loading' do
before do
store.store
store.load
end
it 'has no checksum' do
expect(store[other_item]).to be_nil
end
end
end
end
nanoc-4.11.0/nanoc/spec/nanoc/base/repos/compiled_content_cache_spec.rb000066400000000000000000000032031340050175000260640ustar00rootroot00000000000000# frozen_string_literal: true
describe Nanoc::Int::CompiledContentCache do
let(:cache) { described_class.new(config: config) }
let(:items) { [item] }
let(:item) { Nanoc::Int::Item.new('asdf', {}, '/foo.md') }
let(:item_rep) { Nanoc::Int::ItemRep.new(item, :default) }
let(:other_item) { Nanoc::Int::Item.new('asdf', {}, '/sneaky.md') }
let(:other_item_rep) { Nanoc::Int::ItemRep.new(other_item, :default) }
let(:content) { Nanoc::Int::Content.create('omg') }
let(:config) { Nanoc::Int::Configuration.new(dir: Dir.getwd).with_defaults }
it 'has no content by default' do
expect(cache[item_rep]).to be_nil
end
context 'setting content on known item' do
before { cache[item_rep] = { last: content } }
it 'has content' do
expect(cache[item_rep][:last].string).to eql('omg')
end
context 'after storing and loading' do
before do
cache.store
cache.load
end
it 'has content' do
expect(cache[item_rep][:last].string).to eql('omg')
end
end
end
context 'setting content on unknown item' do
before { cache[other_item_rep] = { last: content } }
it 'has content' do
expect(cache[other_item_rep][:last].string).to eql('omg')
end
context 'after storing and loading' do
before do
cache.store
cache.load
end
it 'has content' do
expect(cache[other_item_rep][:last].string).to eql('omg')
end
end
context 'after pruning' do
before do
cache.prune(items: items)
end
it 'has no content' do
expect(cache[other_item_rep]).to be_nil
end
end
end
end
nanoc-4.11.0/nanoc/spec/nanoc/base/repos/config_loader_spec.rb000066400000000000000000000176111340050175000242160ustar00rootroot00000000000000# frozen_string_literal: true
describe Nanoc::Int::ConfigLoader do
let(:loader) { described_class.new }
describe '#new_from_cwd' do
subject { loader.new_from_cwd }
context 'no config file present' do
it 'errors' do
expect { subject }.to raise_error(
Nanoc::Int::ConfigLoader::NoConfigFileFoundError,
)
end
end
context 'YAML config file present' do
before do
File.write('nanoc.yaml', YAML.dump(foo: 'bar'))
end
it 'returns a configuration' do
expect(subject).to be_a(Nanoc::Int::Configuration)
end
it 'has the defaults' do
expect(subject[:output_dir]).to eq('output')
end
it 'has the custom option' do
expect(subject[:foo]).to eq('bar')
end
end
context 'TOML config file present' do
around do |ex|
Nanoc::Feature.enable(Nanoc::Feature::TOML) do
ex.run
end
end
before do
File.write('nanoc.toml', 'foo = "bar"')
end
it 'returns a configuration' do
expect(subject).to be_a(Nanoc::Int::Configuration)
end
it 'has the defaults' do
expect(subject[:output_dir]).to eq('output')
end
it 'has the custom option' do
expect(subject[:foo]).to eq('bar')
end
end
context 'YAML config file and YAML parent present' do
before do
File.write('nanoc.yaml', YAML.dump(parent_config_file: 'parent.yaml'))
File.write('parent.yaml', YAML.dump(foo: 'bar'))
end
it 'returns the configuration' do
expect(subject).to be_a(Nanoc::Int::Configuration)
end
it 'has the defaults' do
expect(subject[:output_dir]).to eq('output')
end
it 'has the custom option' do
expect(subject[:foo]).to eq('bar')
end
it 'does not include parent config option' do
expect(subject[:parent_config_file]).to be_nil
end
end
context 'TOML config file and TOML parent present' do
around do |ex|
Nanoc::Feature.enable(Nanoc::Feature::TOML) do
ex.run
end
end
before do
File.write('nanoc.toml', 'parent_config_file = "parent.toml"')
File.write('parent.toml', 'foo = "bar"')
end
it 'returns the configuration' do
expect(subject).to be_a(Nanoc::Int::Configuration)
end
it 'has the defaults' do
expect(subject[:output_dir]).to eq('output')
end
it 'has the custom option' do
expect(subject[:foo]).to eq('bar')
end
it 'does not include parent config option' do
expect(subject[:parent_config_file]).to be_nil
end
end
context 'config file present, environment defined' do
let(:active_env_name) { 'default' }
let(:config) do
{
foo: 'bar',
tofoo: 'bar',
environments: {
test: { foo: 'test-bar' },
default: { foo: 'default-bar' },
},
}
end
before do
File.write('nanoc.yaml', YAML.dump(config))
end
before do
expect(ENV).to receive(:fetch).with('NANOC_ENV', 'default').and_return(active_env_name)
end
it 'returns the configuration' do
expect(subject).to be_a(Nanoc::Int::Configuration)
end
it 'has option defined not within environments' do
expect(subject[:tofoo]).to eq('bar')
end
context 'current env is test' do
let(:active_env_name) { 'test' }
it 'has the test environment custom option' do
expect(subject[:foo]).to eq('test-bar')
end
end
it 'has the default environment custom option' do
expect(subject[:foo]).to eq('default-bar')
end
end
end
describe '.cwd_is_nanoc_site? + .config_filename_for_cwd' do
context 'no config files' do
it 'is not considered a nanoc site dir' do
expect(described_class.cwd_is_nanoc_site?).to eq(false)
expect(described_class.config_filename_for_cwd).to be_nil
end
end
context 'nanoc.yaml config file' do
before do
File.write('nanoc.yaml', 'stuff')
end
it 'is considered a nanoc site dir' do
expect(described_class.cwd_is_nanoc_site?).to eq(true)
expect(described_class.config_filename_for_cwd).to eq(File.expand_path('nanoc.yaml'))
end
end
context 'config.yaml config file' do
before do
File.write('config.yaml', 'stuff')
end
it 'is considered a nanoc site dir' do
expect(described_class.cwd_is_nanoc_site?).to eq(true)
expect(described_class.config_filename_for_cwd).to eq(File.expand_path('config.yaml'))
end
end
end
describe '#apply_parent_config' do
subject { loader.apply_parent_config(config, processed_paths) }
let(:config) { Nanoc::Int::Configuration.new(dir: Dir.getwd, hash: { foo: 'bar' }) }
let(:processed_paths) { ['nanoc.yaml'] }
context 'no parent_config_file' do
it 'returns self' do
expect(subject).to eq(config)
end
end
context 'parent config file is set' do
let(:config) do
Nanoc::Int::Configuration.new(dir: Dir.getwd, hash: { parent_config_file: 'foo.yaml', foo: 'bar' })
end
context 'parent config file is not present' do
it 'errors' do
expect { subject }.to raise_error(
Nanoc::Int::ConfigLoader::NoParentConfigFileFoundError,
)
end
end
context 'parent config file is present' do
context 'parent-child cycle' do
before do
File.write('foo.yaml', 'parent_config_file: bar.yaml')
File.write('bar.yaml', 'parent_config_file: foo.yaml')
end
it 'errors' do
expect { subject }.to raise_error(
Nanoc::Int::ConfigLoader::CyclicalConfigFileError,
)
end
end
context 'self parent-child cycle' do
before do
File.write('foo.yaml', 'parent_config_file: foo.yaml')
end
it 'errors' do
expect { subject }.to raise_error(
Nanoc::Int::ConfigLoader::CyclicalConfigFileError,
)
end
end
context 'no parent-child cycle' do
before do
File.write('foo.yaml', 'animal: giraffe')
end
it 'returns a configuration' do
expect(subject).to be_a(Nanoc::Int::Configuration)
end
it 'has no defaults (added in #new_from_cwd only)' do
expect(subject[:output_dir]).to be_nil
end
it 'inherits options from parent' do
expect(subject[:animal]).to eq('giraffe')
end
it 'takes options from child' do
expect(subject[:foo]).to eq('bar')
end
it 'does not include parent config option' do
expect(subject[:parent_config_file]).to be_nil
end
end
context 'long parent chain' do
before do
File.write('foo.yaml', "parrots: 43\nparent_config_file: bar.yaml\n")
File.write('bar.yaml', "day_one: lasers\nslugs: false\n")
end
it 'returns a configuration' do
expect(subject).to be_a(Nanoc::Int::Configuration)
end
it 'has no defaults (added in #new_from_cwd only)' do
expect(subject[:output_dir]).to be_nil
end
it 'inherits options from grandparent' do
expect(subject[:day_one]).to eq('lasers')
expect(subject[:slugs]).to eq(false)
end
it 'inherits options from parent' do
expect(subject[:parrots]).to eq(43)
end
it 'takes options from child' do
expect(subject[:foo]).to eq('bar')
end
it 'does not include parent config option' do
expect(subject[:parent_config_file]).to be_nil
end
end
end
end
end
end
nanoc-4.11.0/nanoc/spec/nanoc/base/repos/data_source_spec.rb000066400000000000000000000062371340050175000237160ustar00rootroot00000000000000# frozen_string_literal: true
describe Nanoc::DataSource, stdio: true do
subject(:data_source) do
described_class.new({}, nil, nil, {})
end
it 'has an empty #up implementation' do
data_source.up
end
it 'has an empty #down implementation' do
data_source.down
end
it 'returns empty #items' do
expect(data_source.items).to be_empty
end
it 'returns empty #layouts' do
expect(data_source.layouts).to be_empty
end
describe '#new_item' do
it 'supports checksum data' do
item = data_source.new_item('stuff', { title: 'Stuff!' }, '/asdf', checksum_data: 'abcdef')
expect(item.content.string).to eql('stuff')
expect(item.attributes[:title]).to eql('Stuff!')
expect(item.identifier).to eql(Nanoc::Identifier.new('/asdf'))
expect(item.checksum_data).to eql('abcdef')
end
it 'supports content/attributes checksum data' do
item = data_source.new_item('stuff', { title: 'Stuff!' }, '/asdf', content_checksum_data: 'con-cs', attributes_checksum_data: 'attr-cs')
expect(item.content.string).to eql('stuff')
expect(item.attributes[:title]).to eql('Stuff!')
expect(item.identifier).to eql(Nanoc::Identifier.new('/asdf'))
expect(item.content_checksum_data).to eql('con-cs')
expect(item.attributes_checksum_data).to eql('attr-cs')
end
end
describe '#new_layout' do
it 'supports checksum data' do
layout = data_source.new_layout('stuff', { title: 'Stuff!' }, '/asdf', checksum_data: 'abcdef')
expect(layout.content.string).to eql('stuff')
expect(layout.attributes[:title]).to eql('Stuff!')
expect(layout.identifier).to eql(Nanoc::Identifier.new('/asdf'))
expect(layout.checksum_data).to eql('abcdef')
end
it 'supports content/attributes checksum data' do
layout = data_source.new_layout('stuff', { title: 'Stuff!' }, '/asdf', content_checksum_data: 'con-cs', attributes_checksum_data: 'attr-cs')
expect(layout.content.string).to eql('stuff')
expect(layout.attributes[:title]).to eql('Stuff!')
expect(layout.identifier).to eql(Nanoc::Identifier.new('/asdf'))
expect(layout.content_checksum_data).to eql('con-cs')
expect(layout.attributes_checksum_data).to eql('attr-cs')
end
end
describe '#item_changes' do
subject { data_source.item_changes }
it 'warns' do
expect { subject }.to output("Caution: Data source nil does not implement #item_changes; live compilation will not pick up changes in this data source.\n").to_stderr
end
it 'never yields anything' do
q = SizedQueue.new(1)
Thread.new { subject.each { |c| q << c } }
sleep 0.1
expect { q.pop(true) }.to raise_error(ThreadError)
end
end
describe '#layout_changes' do
subject { data_source.layout_changes }
it 'warns' do
expect { subject }.to output("Caution: Data source nil does not implement #layout_changes; live compilation will not pick up changes in this data source.\n").to_stderr
end
it 'never yields anything' do
q = SizedQueue.new(1)
Thread.new { subject.each { |c| q << c } }
sleep 0.1
expect { q.pop(true) }.to raise_error(ThreadError)
end
end
end
nanoc-4.11.0/nanoc/spec/nanoc/base/repos/dependency_store_spec.rb000066400000000000000000000417271340050175000247620ustar00rootroot00000000000000# frozen_string_literal: true
describe Nanoc::Int::DependencyStore do
let(:store) { described_class.new(items, layouts, config) }
let(:item_a) { Nanoc::Int::Item.new('a', {}, '/a.md') }
let(:item_b) { Nanoc::Int::Item.new('b', {}, '/b.md') }
let(:item_c) { Nanoc::Int::Item.new('c', {}, '/c.md') }
let(:layout_a) { Nanoc::Int::Layout.new('la', {}, '/la.md') }
let(:layout_b) { Nanoc::Int::Layout.new('lb', {}, '/lb.md') }
let(:items) { Nanoc::Int::ItemCollection.new(config, [item_a, item_b, item_c]) }
let(:layouts) { Nanoc::Int::LayoutCollection.new(config, [layout_a, layout_b]) }
let(:config) { Nanoc::Int::Configuration.new(dir: Dir.getwd).with_defaults }
it 'is empty by default' do
expect(store.objects_causing_outdatedness_of(item_a)).to be_empty
expect(store.objects_causing_outdatedness_of(item_b)).to be_empty
expect(store.objects_causing_outdatedness_of(item_c)).to be_empty
expect(store.objects_causing_outdatedness_of(layout_a)).to be_empty
expect(store.objects_causing_outdatedness_of(layout_b)).to be_empty
end
describe '#dependencies_causing_outdatedness_of' do
context 'no dependencies' do
it 'returns nothing for each' do
expect(store.dependencies_causing_outdatedness_of(item_a)).to be_empty
expect(store.dependencies_causing_outdatedness_of(item_b)).to be_empty
expect(store.dependencies_causing_outdatedness_of(item_c)).to be_empty
end
end
context 'one dependency' do
context 'dependency on config, no props' do
before do
store.record_dependency(item_a, config)
end
it 'returns one dependency' do
deps = store.dependencies_causing_outdatedness_of(item_a)
expect(deps.size).to eql(1)
end
it 'returns dependency from a onto config' do
deps = store.dependencies_causing_outdatedness_of(item_a)
expect(deps[0].from).to eql(config)
expect(deps[0].to).to eql(item_a)
end
it 'returns true for all props by default' do
deps = store.dependencies_causing_outdatedness_of(item_a)
expect(deps[0].props.raw_content?).to eq(true)
expect(deps[0].props.attributes?).to eq(true)
expect(deps[0].props.compiled_content?).to eq(true)
expect(deps[0].props.path?).to eq(true)
end
it 'returns nothing for the others' do
expect(store.dependencies_causing_outdatedness_of(item_b)).to be_empty
expect(store.dependencies_causing_outdatedness_of(item_c)).to be_empty
end
end
context 'dependency on config, generic attributes prop' do
before do
store.record_dependency(item_a, config, attributes: true)
end
it 'returns false for all unspecified props' do
deps = store.dependencies_causing_outdatedness_of(item_a)
expect(deps[0].props.raw_content?).to eq(false)
expect(deps[0].props.compiled_content?).to eq(false)
expect(deps[0].props.path?).to eq(false)
end
it 'returns the specified props' do
deps = store.dependencies_causing_outdatedness_of(item_a)
expect(deps[0].props.attributes?).to eq(true)
end
end
context 'dependency on config, specific attributes prop' do
before do
store.record_dependency(item_a, config, attributes: [:donkey])
end
it 'returns false for all unspecified props' do
deps = store.dependencies_causing_outdatedness_of(item_a)
expect(deps[0].props.raw_content?).to eq(false)
expect(deps[0].props.compiled_content?).to eq(false)
expect(deps[0].props.path?).to eq(false)
end
it 'returns the specified props' do
deps = store.dependencies_causing_outdatedness_of(item_a)
expect(deps[0].props.attributes?).to eq(true)
expect(deps[0].props.attributes).to contain_exactly(:donkey)
end
end
context 'dependency on items, generic prop' do
before do
store.record_dependency(item_a, items)
end
it 'creates one dependency' do
deps = store.dependencies_causing_outdatedness_of(item_a)
expect(deps.size).to eql(1)
end
it 'returns true for all props' do
deps = store.dependencies_causing_outdatedness_of(item_a)
expect(deps[0].props.raw_content?).to be
expect(deps[0].props.compiled_content?).to be
expect(deps[0].props.path?).to be
expect(deps[0].props.attributes?).to be
end
end
context 'no props' do
before do
store.record_dependency(item_a, item_b)
end
it 'returns one dependency' do
deps = store.dependencies_causing_outdatedness_of(item_a)
expect(deps.size).to eql(1)
end
it 'returns dependency from b to a' do
deps = store.dependencies_causing_outdatedness_of(item_a)
expect(deps[0].from).to eql(item_b)
expect(deps[0].to).to eql(item_a)
end
it 'returns true for all props by default' do
deps = store.dependencies_causing_outdatedness_of(item_a)
expect(deps[0].props.raw_content?).to eq(true)
expect(deps[0].props.attributes?).to eq(true)
expect(deps[0].props.compiled_content?).to eq(true)
expect(deps[0].props.path?).to eq(true)
end
it 'returns nothing for the others' do
expect(store.dependencies_causing_outdatedness_of(item_b)).to be_empty
expect(store.dependencies_causing_outdatedness_of(item_c)).to be_empty
end
end
context 'one prop' do
before do
store.record_dependency(item_a, item_b, compiled_content: true)
end
it 'returns false for all unspecified props' do
deps = store.dependencies_causing_outdatedness_of(item_a)
expect(deps[0].props.raw_content?).to eq(false)
expect(deps[0].props.attributes?).to eq(false)
expect(deps[0].props.path?).to eq(false)
end
it 'returns the specified props' do
deps = store.dependencies_causing_outdatedness_of(item_a)
expect(deps[0].props.compiled_content?).to eq(true)
end
end
context 'two props' do
before do
store.record_dependency(item_a, item_b, compiled_content: true)
store.record_dependency(item_a, item_b, attributes: true)
end
it 'returns false for all unspecified props' do
deps = store.dependencies_causing_outdatedness_of(item_a)
expect(deps[0].props.raw_content?).to eq(false)
expect(deps[0].props.path?).to eq(false)
end
it 'returns the specified props' do
deps = store.dependencies_causing_outdatedness_of(item_a)
expect(deps[0].props.attributes?).to eq(true)
expect(deps[0].props.compiled_content?).to eq(true)
end
end
end
context 'two dependency in a chain' do
before do
store.record_dependency(item_a, item_b)
store.record_dependency(item_b, item_c)
end
it 'returns one dependency for object A' do
deps = store.dependencies_causing_outdatedness_of(item_a)
expect(deps.size).to eql(1)
expect(deps[0].from).to eql(item_b)
end
it 'returns one dependency for object B' do
deps = store.dependencies_causing_outdatedness_of(item_b)
expect(deps.size).to eql(1)
expect(deps[0].from).to eql(item_c)
end
it 'returns nothing for the others' do
expect(store.dependencies_causing_outdatedness_of(item_c)).to be_empty
end
end
end
describe 'reloading - item a -> b' do
before do
store.record_dependency(item_a, item_b, compiled_content: true)
store.record_dependency(item_a, item_b, attributes: true)
store.store
end
let(:reloaded_store) do
described_class.new(items_after, layouts, config).tap(&:load)
end
context 'no new items' do
let(:items_after) { items }
it 'has the right dependencies for item A' do
deps = reloaded_store.dependencies_causing_outdatedness_of(item_a)
expect(deps.size).to eql(1)
expect(deps[0].from).to eql(item_b)
expect(deps[0].to).to eql(item_a)
expect(deps[0].props.raw_content?).to eq(false)
expect(deps[0].props.attributes?).to eq(true)
expect(deps[0].props.compiled_content?).to eq(true)
expect(deps[0].props.path?).to eq(false)
end
it 'has the right dependencies for item B' do
deps = reloaded_store.dependencies_causing_outdatedness_of(item_b)
expect(deps).to be_empty
end
it 'has the right dependencies for item C' do
deps = reloaded_store.dependencies_causing_outdatedness_of(item_c)
expect(deps).to be_empty
end
end
context 'one new item' do
let(:items_after) do
Nanoc::Int::ItemCollection.new(config, [item_a, item_b, item_c, item_d])
end
let(:item_d) { Nanoc::Int::Item.new('d', {}, '/d.md') }
it 'does not mark items as outdated' do
expect(reloaded_store.objects_causing_outdatedness_of(item_a)).not_to include(item_d)
expect(reloaded_store.objects_causing_outdatedness_of(item_b)).not_to include(item_d)
expect(reloaded_store.objects_causing_outdatedness_of(item_c)).not_to include(item_d)
expect(reloaded_store.objects_causing_outdatedness_of(item_d)).not_to include(item_d)
end
end
context 'unrelated item removed' do
let(:items_after) do
Nanoc::Int::ItemCollection.new(config, [item_a, item_b])
end
it 'does not mark items as outdated' do
expect(reloaded_store.objects_causing_outdatedness_of(item_a)).to eq([item_b])
expect(reloaded_store.objects_causing_outdatedness_of(item_b)).to be_empty
expect(reloaded_store.objects_causing_outdatedness_of(item_c)).to be_empty
end
end
context 'related item removed' do
let(:items_after) do
Nanoc::Int::ItemCollection.new(config, [item_a, item_c])
end
it 'does not mark items as outdated' do
expect(reloaded_store.objects_causing_outdatedness_of(item_a)).to eq([nil])
expect(reloaded_store.objects_causing_outdatedness_of(item_b)).to be_empty
expect(reloaded_store.objects_causing_outdatedness_of(item_c)).to be_empty
end
end
end
describe 'reloading - item a -> config' do
before do
store.record_dependency(item_a, config, attributes: [:donkey])
store.store
store.load
end
it 'has the right dependencies for item A' do
deps = store.dependencies_causing_outdatedness_of(item_a)
expect(deps.size).to eql(1)
expect(deps[0].from).to eql(config)
expect(deps[0].to).to eql(item_a)
expect(deps[0].props.raw_content?).to eq(false)
expect(deps[0].props.attributes?).to eq(true)
expect(deps[0].props.attributes).to contain_exactly(:donkey)
expect(deps[0].props.compiled_content?).to eq(false)
expect(deps[0].props.path?).to eq(false)
end
it 'has the right dependencies for item B' do
deps = store.dependencies_causing_outdatedness_of(item_b)
expect(deps).to be_empty
end
it 'has the right dependencies for item C' do
deps = store.dependencies_causing_outdatedness_of(item_c)
expect(deps).to be_empty
end
end
shared_examples 'records dependencies' do
context 'no props' do
subject { store.record_dependency(source_obj, item_b) }
it 'records a dependency' do
expect { subject }
.to change { store.objects_causing_outdatedness_of(source_obj) }
.from([])
.to([item_b])
end
it 'ignores all other objects' do
subject
expect(other_items).to all(satisfy { |o| store.dependencies_causing_outdatedness_of(o).empty? })
end
context 'dependency on self' do
subject { store.record_dependency(source_obj, item_a) }
it 'does not create dependency on self' do
expect { subject }
.not_to change { store.objects_causing_outdatedness_of(source_obj) }
end
end
context 'two dependencies' do
subject do
store.record_dependency(source_obj, item_b)
store.record_dependency(source_obj, item_b)
end
it 'does not create duplicate dependencies' do
expect { subject }
.to change { store.objects_causing_outdatedness_of(source_obj) }
.from([])
.to([item_b])
end
end
context 'dependency to nil' do
subject { store.record_dependency(source_obj, nil) }
it 'creates a dependency to nil' do
expect { subject }
.to change { store.objects_causing_outdatedness_of(source_obj) }
.from([])
.to([nil])
end
end
context 'dependency from nil' do
subject { store.record_dependency(nil, item_b) }
it 'does not create a dependency from nil' do
expect { subject }
.not_to change { store.objects_causing_outdatedness_of(item_b) }
end
end
end
context 'compiled content prop' do
subject { store.record_dependency(source_obj, target_obj, compiled_content: true) }
it 'records a dependency' do
expect { subject }
.to change { store.objects_causing_outdatedness_of(source_obj) }
.from([])
.to([target_obj])
end
it 'records a dependency with the right props' do
subject
deps = store.dependencies_causing_outdatedness_of(source_obj)
expect(deps.first.props.attributes?).not_to be
expect(deps.first.props.compiled_content?).to be
end
it 'ignores all other objects' do
subject
expect(other_items).to all(satisfy { |o| store.dependencies_causing_outdatedness_of(o).empty? })
end
end
context 'attribute prop (true)' do
subject { store.record_dependency(source_obj, target_obj, attributes: true) }
it 'records a dependency' do
expect { subject }
.to change { store.objects_causing_outdatedness_of(source_obj) }
.from([])
.to([target_obj])
end
it 'records a dependency with the right props' do
subject
deps = store.dependencies_causing_outdatedness_of(source_obj)
expect(deps.first.props.attributes?).to be
expect(deps.first.props.attributes).to be
expect(deps.first.props.compiled_content?).not_to be
end
it 'ignores all other objects' do
subject
expect(other_items).to all(satisfy { |o| store.dependencies_causing_outdatedness_of(o).empty? })
end
end
context 'attribute prop (true)' do
subject { store.record_dependency(source_obj, target_obj, attributes: [:giraffe]) }
it 'records a dependency' do
expect { subject }
.to change { store.objects_causing_outdatedness_of(source_obj) }
.from([])
.to([target_obj])
end
it 'records a dependency with the right props' do
subject
deps = store.dependencies_causing_outdatedness_of(source_obj)
expect(deps.first.props.attributes?).to be
expect(deps.first.props.attributes).to match_array([:giraffe])
expect(deps.first.props.compiled_content?).not_to be
end
it 'ignores all other objects' do
subject
expect(other_items).to all(satisfy { |o| store.dependencies_causing_outdatedness_of(o).empty? })
end
end
end
describe '#record_dependency' do
context 'item on item' do
let(:source_obj) { item_a }
let(:target_obj) { item_b }
let(:other_items) { [item_c] }
include_examples 'records dependencies'
end
context 'item on layout' do
let(:source_obj) { item_a }
let(:target_obj) { layout_a }
let(:other_items) { [item_b, item_c] }
include_examples 'records dependencies'
end
context 'item on config' do
let(:source_obj) { item_a }
let(:target_obj) { config }
let(:other_items) { [item_b, item_c] }
include_examples 'records dependencies'
end
end
describe '#forget_dependencies_for' do
before do
store.record_dependency(item_a, item_b)
store.record_dependency(item_a, item_c)
store.record_dependency(item_b, item_a)
store.record_dependency(item_b, item_c)
store.record_dependency(item_c, item_a)
store.record_dependency(item_c, item_b)
end
subject { store.forget_dependencies_for(item_b) }
it 'removes dependencies from item_a' do
expect { subject }
.not_to change { store.objects_causing_outdatedness_of(item_a) }
end
it 'removes dependencies from item_b' do
expect { subject }
.to change { store.objects_causing_outdatedness_of(item_b) }
.from(match_array([item_a, item_c]))
.to(be_empty)
end
it 'removes dependencies from item_c' do
expect { subject }
.not_to change { store.objects_causing_outdatedness_of(item_c) }
end
end
end
nanoc-4.11.0/nanoc/spec/nanoc/base/repos/in_mem_data_source_spec.rb000066400000000000000000000015031340050175000252310ustar00rootroot00000000000000# frozen_string_literal: true
describe Nanoc::Int::InMemDataSource, stdio: true do
let(:klass) do
Class.new(Nanoc::DataSource) do
def item_changes
%i[one_foo one_bar]
end
def layout_changes
%i[one_foo one_bar]
end
end
end
let(:original_data_source) do
klass.new({}, nil, nil, {})
end
subject(:data_source) do
described_class.new([], [], original_data_source)
end
describe '#item_changes' do
subject { data_source.item_changes }
it 'yields changes from the original' do
expect(subject).to eq(original_data_source.item_changes)
end
end
describe '#layout_changes' do
subject { data_source.layout_changes }
it 'yields changes from the original' do
expect(subject).to eq(original_data_source.layout_changes)
end
end
end
nanoc-4.11.0/nanoc/spec/nanoc/base/repos/outdatedness_store_spec.rb000066400000000000000000000024201340050175000253310ustar00rootroot00000000000000# frozen_string_literal: true
describe Nanoc::Int::OutdatednessStore do
subject(:store) { described_class.new(config: config) }
let(:item) { Nanoc::Int::Item.new('foo', {}, '/foo.md') }
let(:rep) { Nanoc::Int::ItemRep.new(item, :foo) }
let(:config) { Nanoc::Int::Configuration.new(dir: Dir.getwd).with_defaults }
let(:items) { [] }
let(:layouts) { [] }
let(:code_snippets) { [] }
describe '#include?, #add and #remove' do
subject { store.include?(rep) }
context 'nothing added' do
it { is_expected.not_to be }
end
context 'rep added' do
before { store.add(rep) }
it { is_expected.to be }
end
context 'rep added and removed' do
before do
store.add(rep)
store.remove(rep)
end
it { is_expected.not_to be }
end
context 'rep added, removed, and added again' do
before do
store.add(rep)
store.remove(rep)
store.add(rep)
end
it { is_expected.to be }
end
end
describe 'reloading' do
subject do
store.store
store.load
store.include?(rep)
end
context 'not added' do
it { is_expected.not_to be }
end
context 'added' do
before { store.add(rep) }
it { is_expected.to be }
end
end
end
nanoc-4.11.0/nanoc/spec/nanoc/base/repos/prefixed_data_source_spec.rb000066400000000000000000000015241340050175000255760ustar00rootroot00000000000000# frozen_string_literal: true
describe Nanoc::Int::PrefixedDataSource, stdio: true do
let(:klass) do
Class.new(Nanoc::DataSource) do
def item_changes
%i[one_foo one_bar]
end
def layout_changes
%i[one_foo one_bar]
end
end
end
let(:original_data_source) do
klass.new({}, nil, nil, {})
end
subject(:data_source) do
described_class.new(original_data_source, '/itemz', '/layoutz')
end
describe '#item_changes' do
subject { data_source.item_changes }
it 'yields changes from the original' do
expect(subject).to eq(original_data_source.item_changes)
end
end
describe '#layout_changes' do
subject { data_source.layout_changes }
it 'yields changes from the original' do
expect(subject).to eq(original_data_source.layout_changes)
end
end
end
nanoc-4.11.0/nanoc/spec/nanoc/base/repos/site_loader_spec.rb000066400000000000000000000157441340050175000237220ustar00rootroot00000000000000# frozen_string_literal: true
describe Nanoc::Int::SiteLoader do
let(:loader) { described_class.new }
describe '#new_from_cwd' do
subject { loader.new_from_cwd }
context 'no config file' do
it 'errors' do
expect { subject }.to raise_error(
Nanoc::Int::ConfigLoader::NoConfigFileFoundError,
)
end
end
shared_examples 'a directory with a config file' do
it 'has the default configuration' do
expect(subject.config).to be_a(Nanoc::Int::Configuration)
expect(subject.config[:index_filenames]).to eq(['index.html'])
expect(subject.config[:foo]).to eq('bar')
end
it 'has no code snippets' do
expect(subject.code_snippets).to be_empty
end
it 'has no items' do
expect(subject.items).to be_empty
end
it 'has no layouts' do
expect(subject.layouts).to be_empty
end
context 'some items, layouts, and code snippets' do
before do
FileUtils.mkdir_p('lib')
File.write('lib/foo.rb', '$spirit_animal = :donkey')
FileUtils.mkdir_p('content')
File.write('content/about.md', 'I am Denis!')
FileUtils.mkdir_p('layouts')
File.write('layouts/page.erb', '<%= yield %>')
end
it 'has a code snippet' do
expect(subject.code_snippets.size).to eq(1)
expect(subject.code_snippets[0].data).to eq('$spirit_animal = :donkey')
end
it 'has an item' do
expect(subject.items.size).to eq(1)
expect(subject.items['/about.md'].content).to be_a(Nanoc::Int::TextualContent)
expect(subject.items['/about.md'].content.string).to eq('I am Denis!')
expect(subject.items['/about.md'].attributes[:content_filename])
.to eq('content/about.md')
expect(subject.items['/about.md'].attributes[:extension])
.to eq('md')
expect(subject.items['/about.md'].attributes[:filename])
.to eq('content/about.md')
expect(subject.items['/about.md'].attributes[:meta_filename])
.to be_nil
expect(subject.items['/about.md'].attributes[:mtime])
.to be > Time.now - 5
expect(subject.items['/about.md'].identifier.to_s).to eq('/about.md')
end
it 'has a layout' do
expect(subject.layouts.size).to eq(1)
expect(subject.layouts['/page.erb'].content).to be_a(Nanoc::Int::TextualContent)
expect(subject.layouts['/page.erb'].content.string).to eq('<%= yield %>')
expect(subject.layouts['/page.erb'].attributes[:content_filename])
.to eq('layouts/page.erb')
expect(subject.layouts['/page.erb'].attributes[:extension])
.to eq('erb')
expect(subject.layouts['/page.erb'].attributes[:filename])
.to eq('layouts/page.erb')
expect(subject.layouts['/page.erb'].attributes[:meta_filename])
.to be_nil
expect(subject.layouts['/page.erb'].attributes[:mtime])
.to be > Time.now - 5
expect(subject.layouts['/page.erb'].identifier.to_s).to eq('/page.erb')
end
end
end
context 'nanoc.yaml config file' do
before do
File.write('nanoc.yaml', "---\nfoo: bar\n")
end
it_behaves_like 'a directory with a config file'
end
context 'config.yaml config file' do
before do
File.write('config.yaml', "---\nfoo: bar\n")
end
it_behaves_like 'a directory with a config file'
end
context 'configuration has non-existant data source' do
before do
File.write('nanoc.yaml', <<-EOS.gsub(/^ {10}/, ''))
data_sources:
- type: eenvaleed
EOS
end
it 'raises an error' do
expect { subject }.to raise_error(Nanoc::Int::Errors::UnknownDataSource)
end
end
context 'environments defined' do
before do
File.write('nanoc.yaml', <<-EOS.gsub(/^ {10}/, ''))
animal: donkey
environments:
staging:
animal: giraffe
EOS
end
before do
expect(ENV).to receive(:fetch).with('NANOC_ENV', 'default').and_return('staging')
end
it 'does not load environment' do
expect(subject.config[:animal]).to eq('giraffe')
end
end
context 'code snippet with data source implementation' do
before do
FileUtils.mkdir_p('lib')
File.write('lib/foo_data_source.rb', <<-EOS.gsub(/^ {10}/, ''))
class FooDataSource < Nanoc::DataSource
identifier :site_loader_spec_sample
def items
[
Nanoc::Int::Item.new(
'Generated content!',
{ generated: true },
'/generated.txt',
)
]
end
end
EOS
File.write('nanoc.yaml', <<-EOS.gsub(/^ {10}/, ''))
data_sources:
- type: site_loader_spec_sample
EOS
end
it 'loads code snippets before items/layouts' do
expect(subject.items.size).to eq(1)
expect(subject.items['/generated.txt'].content).to be_a(Nanoc::Int::TextualContent)
expect(subject.items['/generated.txt'].content.string).to eq('Generated content!')
expect(subject.items['/generated.txt'].attributes).to eq(generated: true)
expect(subject.items['/generated.txt'].identifier.to_s).to eq('/generated.txt')
end
end
end
describe '#code_snippets_from_config' do
subject { loader.send(:code_snippets_from_config, config) }
let(:config) { Nanoc::Int::Configuration.new(dir: Dir.getwd).with_defaults }
before { FileUtils.mkdir_p('lib') }
context 'no explicit encoding specified' do
example do
File.write('lib/asdf.rb', 'hi 🔥', encoding: 'utf-8')
expect(subject.size).to eq(1)
expect(subject.first.data).to eq('hi 🔥')
end
end
context '# encoding: x specified' do
example do
File.write('lib/asdf.rb', "# encoding: iso-8859-1\n\nBRØKEN", encoding: 'iso-8859-1')
expect(subject.size).to eq(1)
expect(subject.first.data).to eq('BRØKEN')
end
end
context '# coding: x specified' do
example do
File.write('lib/asdf.rb', "# coding: iso-8859-1\n\nBRØKEN", encoding: 'iso-8859-1')
expect(subject.size).to eq(1)
expect(subject.first.data).to eq('BRØKEN')
end
end
context '# -*- encoding: x -*- specified' do
example do
File.write('lib/asdf.rb', "# -*- encoding: iso-8859-1 -*-\n\nBRØKEN", encoding: 'iso-8859-1')
expect(subject.size).to eq(1)
expect(subject.first.data).to eq('BRØKEN')
end
end
context '# -*- coding: x -*- specified' do
example do
File.write('lib/asdf.rb', "# -*- coding: iso-8859-1 -*-\n\nBRØKEN", encoding: 'iso-8859-1')
expect(subject.size).to eq(1)
expect(subject.first.data).to eq('BRØKEN')
end
end
end
end
nanoc-4.11.0/nanoc/spec/nanoc/base/repos/snapshot_repo_spec.rb000066400000000000000000000237541340050175000243140ustar00rootroot00000000000000# frozen_string_literal: true
describe Nanoc::Int::SnapshotRepo do
subject(:repo) { described_class.new }
describe '#get' do
subject { repo.get(rep, snapshot_name) }
let(:item) { Nanoc::Int::Item.new('contentz', {}, '/foo.md') }
let(:rep) { Nanoc::Int::ItemRep.new(item, :foo) }
let(:snapshot_name) { :donkey }
context 'rep does not exist in repo' do
it { is_expected.to be_nil }
end
context 'rep exists in repo' do
before { repo.set(rep, :foobar, Nanoc::Int::TextualContent.new('other content')) }
context 'snapshot does not exist in repo' do
it { is_expected.to be_nil }
end
context 'snapshot exists in repo' do
before { repo.set(rep, :donkey, Nanoc::Int::TextualContent.new('donkey')) }
it { is_expected.to be_some_textual_content('donkey') }
end
end
end
describe '#get_all' do
subject { repo.get_all(rep) }
let(:item) { Nanoc::Int::Item.new('contentz', {}, '/foo.md') }
let(:rep) { Nanoc::Int::ItemRep.new(item, :foo) }
context 'rep does not exist in repo' do
it { is_expected.to eq({}) }
end
context 'rep exists in repo' do
before { repo.set(rep, :foobar, Nanoc::Int::TextualContent.new('donkey')) }
it { is_expected.to match(foobar: some_textual_content('donkey')) }
end
end
describe '#set' do
subject { repo.set(rep, snapshot_name, contents) }
let(:item) { Nanoc::Int::Item.new('contentz', {}, '/foo.md') }
let(:rep) { Nanoc::Int::ItemRep.new(item, :foo) }
let(:snapshot_name) { :donkey }
let(:contents) { Nanoc::Int::TextualContent.new('donkey') }
it 'changes the given rep+snapshot' do
expect { subject }
.to change { repo.get(rep, snapshot_name) }
.from(nil)
.to(some_textual_content('donkey'))
end
end
describe '#set_all' do
subject { repo.set_all(rep, contents_by_snapshot) }
let(:other_item) { Nanoc::Int::Item.new('contentz', {}, '/foo.md') }
let(:other_rep) { Nanoc::Int::ItemRep.new(other_item, :foo) }
let(:item) { Nanoc::Int::Item.new('contentz', {}, '/foo.md') }
let(:rep) { Nanoc::Int::ItemRep.new(item, :foo) }
let(:contents_by_snapshot) { { donkey: Nanoc::Int::TextualContent.new('donkey') } }
it 'changes the given rep+snapshot' do
expect { subject }
.to change { repo.get(rep, :donkey) }
.from(nil)
.to(some_textual_content('donkey'))
end
it 'leaves other reps intact' do
expect { subject }
.not_to change { repo.get(other_rep, :donkey) }
end
it 'leaves other snapshots intact' do
expect { subject }
.not_to change { repo.get(rep, :giraffe) }
end
end
describe '#compiled_content' do
subject { repo.compiled_content(rep: rep, snapshot: snapshot_name) }
let(:snapshot_name) { raise 'override me' }
let(:item) { Nanoc::Int::Item.new('contentz', {}, '/foo.md') }
let(:rep) { Nanoc::Int::ItemRep.new(item, :foo) }
shared_examples 'a non-moving snapshot with content' do
context 'no snapshot def' do
it 'raises' do
expect { subject }.to raise_error(Nanoc::Int::Errors::NoSuchSnapshot)
end
end
context 'snapshot def exists' do
before do
rep.snapshot_defs = [Nanoc::Int::SnapshotDef.new(snapshot_name, binary: false)]
repo.set_all(rep, snapshot_name => content)
end
context 'content is textual' do
let(:content) { Nanoc::Int::TextualContent.new('hellos') }
it { is_expected.to eql('hellos') }
end
context 'content is binary' do
before { File.write('donkey.dat', 'binary data') }
let(:content) { Nanoc::Int::BinaryContent.new(File.expand_path('donkey.dat')) }
it 'raises' do
expect { subject }.to raise_error(Nanoc::Int::Errors::CannotGetCompiledContentOfBinaryItem, 'You cannot access the compiled content of a binary item representation (but you can access the path). The offending item rep is /foo.md (rep name :foo).')
end
end
end
end
shared_examples 'a non-moving snapshot' do
include_examples 'a non-moving snapshot with content'
context 'snapshot def exists, but not content' do
before do
rep.snapshot_defs = [Nanoc::Int::SnapshotDef.new(snapshot_name, binary: false)]
repo.set_all(rep, {})
end
it 'errors' do
expect { subject }.to yield_from_fiber(an_instance_of(Nanoc::Int::Errors::UnmetDependency))
end
end
end
shared_examples 'snapshot :last' do
context 'no snapshot def' do
it 'errors' do
expect { subject }.to raise_error(Nanoc::Int::Errors::NoSuchSnapshot)
end
end
context 'snapshot exists' do
context 'snapshot is not final' do
before do
rep.snapshot_defs = [Nanoc::Int::SnapshotDef.new(snapshot_name, binary: false)]
end
context 'snapshot content does not exist' do
before do
repo.set_all(rep, {})
end
it 'errors' do
expect { subject }.to yield_from_fiber(an_instance_of(Nanoc::Int::Errors::UnmetDependency))
end
end
context 'snapshot content exists' do
context 'content is textual' do
before do
repo.set(rep, snapshot_name, Nanoc::Int::TextualContent.new('hellos'))
end
context 'not compiled' do
before { rep.compiled = false }
it 'raises' do
expect { subject }.to yield_from_fiber(an_instance_of(Nanoc::Int::Errors::UnmetDependency))
end
end
context 'compiled' do
before { rep.compiled = true }
it { is_expected.to eql('hellos') }
end
end
context 'content is binary' do
before do
File.write('donkey.dat', 'binary data')
repo.set(rep, snapshot_name, Nanoc::Int::BinaryContent.new(File.expand_path('donkey.dat')))
end
context 'not compiled' do
before { rep.compiled = false }
it 'raises' do
expect { subject }.to yield_from_fiber(an_instance_of(Nanoc::Int::Errors::UnmetDependency))
end
end
context 'compiled' do
before { rep.compiled = true }
it 'raises' do
expect { subject }.to raise_error(Nanoc::Int::Errors::CannotGetCompiledContentOfBinaryItem, 'You cannot access the compiled content of a binary item representation (but you can access the path). The offending item rep is /foo.md (rep name :foo).')
end
end
end
end
end
context 'snapshot is final' do
before do
rep.snapshot_defs = [Nanoc::Int::SnapshotDef.new(snapshot_name, binary: false)]
end
context 'snapshot content does not exist' do
before do
repo.set_all(rep, {})
end
it 'errors' do
expect { subject }.to yield_from_fiber(an_instance_of(Nanoc::Int::Errors::UnmetDependency))
end
end
context 'snapshot content exists' do
context 'content is textual' do
before do
repo.set(rep, snapshot_name, Nanoc::Int::TextualContent.new('hellos'))
end
context 'not compiled' do
before { rep.compiled = false }
it 'errors' do
expect { subject }.to yield_from_fiber(an_instance_of(Nanoc::Int::Errors::UnmetDependency))
end
end
context 'compiled' do
before { rep.compiled = true }
it { is_expected.to eql('hellos') }
end
end
context 'content is binary' do
before do
File.write('donkey.dat', 'binary data')
repo.set(rep, snapshot_name, Nanoc::Int::BinaryContent.new(File.expand_path('donkey.dat')))
end
context 'not compiled' do
before { rep.compiled = false }
it 'raises' do
expect { subject }.to yield_from_fiber(an_instance_of(Nanoc::Int::Errors::UnmetDependency))
end
end
context 'compiled' do
before { rep.compiled = true }
it 'raises' do
expect { subject }.to raise_error(Nanoc::Int::Errors::CannotGetCompiledContentOfBinaryItem, 'You cannot access the compiled content of a binary item representation (but you can access the path). The offending item rep is /foo.md (rep name :foo).')
end
end
end
end
end
end
end
context 'snapshot nil' do
let(:snapshot_name) { :last }
subject { repo.compiled_content(rep: rep, snapshot: nil) }
include_examples 'snapshot :last'
end
context 'snapshot not specified' do
subject { repo.compiled_content(rep: rep) }
context 'pre exists' do
before { repo.set(rep, :pre, Nanoc::Int::TextualContent.new('omg')) }
let(:snapshot_name) { :pre }
include_examples 'a non-moving snapshot with content'
end
context 'pre does not exist' do
let(:snapshot_name) { :last }
include_examples 'snapshot :last'
end
end
context 'snapshot :pre specified' do
let(:snapshot_name) { :pre }
include_examples 'a non-moving snapshot'
end
context 'snapshot :post specified' do
let(:snapshot_name) { :post }
include_examples 'a non-moving snapshot'
end
context 'snapshot :last specified' do
let(:snapshot_name) { :last }
include_examples 'snapshot :last'
end
context 'snapshot :donkey specified' do
let(:snapshot_name) { :donkey }
include_examples 'a non-moving snapshot'
end
end
end
nanoc-4.11.0/nanoc/spec/nanoc/base/repos/store_spec.rb000066400000000000000000000067241340050175000225620ustar00rootroot00000000000000# frozen_string_literal: true
describe Nanoc::Int::Store do
describe '#tmp_path_for' do
context 'passing config' do
subject { described_class.tmp_path_for(config: config, store_name: 'giraffes') }
let(:code_snippets) { [] }
let(:items) { [] }
let(:layouts) { [] }
def gen_hash(path)
Digest::SHA1.hexdigest(File.absolute_path(path))[0..12]
end
let(:hash_output) { gen_hash('output') }
let(:hash_output_default) { gen_hash('output-default') }
let(:hash_output_staging) { gen_hash('output-staging') }
let(:hash_output_production) { gen_hash('output-production') }
context 'no env specified' do
let(:config) { Nanoc::Int::Configuration.new(dir: Dir.getwd, hash: config_hash).with_defaults.with_environment }
context 'output dir is unspecified' do
let(:config_hash) { {} }
it { is_expected.to eql(Dir.getwd + "/tmp/nanoc/#{hash_output}/giraffes") }
end
context 'output dir at root is specified' do
let(:config_hash) { { output_dir: 'output-default' } }
it { is_expected.to eql(Dir.getwd + "/tmp/nanoc/#{hash_output_default}/giraffes") }
end
context 'output dir in default env is specified' do
let(:config_hash) { { environments: { default: { output_dir: 'output-default' } } } }
it { is_expected.to eql(Dir.getwd + "/tmp/nanoc/#{hash_output_default}/giraffes") }
end
context 'output dir in other env is specified' do
let(:config_hash) { { environments: { production: { output_dir: 'output-production' } } } }
it { is_expected.to eql(Dir.getwd + "/tmp/nanoc/#{hash_output}/giraffes") }
end
end
context 'env specified' do
let(:config) { Nanoc::Int::Configuration.new(env_name: 'staging', dir: Dir.getwd, hash: config_hash).with_defaults.with_environment }
context 'output dir is unspecified' do
let(:config_hash) { {} }
it { is_expected.to eql(Dir.getwd + "/tmp/nanoc/#{hash_output}/giraffes") }
end
context 'output dir at root is specified' do
let(:config_hash) { { output_dir: 'output-default' } }
it { is_expected.to eql(Dir.getwd + "/tmp/nanoc/#{hash_output_default}/giraffes") }
end
context 'output dir in given env is specified' do
let(:config_hash) { { environments: { staging: { output_dir: 'output-staging' } } } }
it { is_expected.to eql(Dir.getwd + "/tmp/nanoc/#{hash_output_staging}/giraffes") }
end
context 'output dir in other env is specified' do
let(:config_hash) { { environments: { production: { output_dir: 'output-production' } } } }
it { is_expected.to eql(Dir.getwd + "/tmp/nanoc/#{hash_output}/giraffes") }
end
end
end
end
let(:test_store_klass) do
Class.new(Nanoc::Int::Store) do
def data
@data
end
def data=(new_data)
@data = new_data
end
end
end
it 'deletes and reloads on error' do
store = test_store_klass.new('test.db', 1)
# Create
store.load
store.data = { fun: 'sure' }
store.store
# Test stored values
store = test_store_klass.new('test.db', 1)
store.load
expect(store.data).to eq(fun: 'sure')
# Mess up
File.write('test.db', 'Damn {}#}%@}$^)@&$&*^#@ broken stores!!!')
# Reload
store = test_store_klass.new('test.db', 1)
store.load
expect(store.data).to be_nil
end
end
nanoc-4.11.0/nanoc/spec/nanoc/base/services/000077500000000000000000000000001340050175000205515ustar00rootroot00000000000000nanoc-4.11.0/nanoc/spec/nanoc/base/services/action_sequence_builder_spec.rb000066400000000000000000000032071340050175000267650ustar00rootroot00000000000000# frozen_string_literal: true
describe Nanoc::Int::ActionSequenceBuilder do
let(:builder) { described_class.new(item_rep) }
let(:item_rep) { Nanoc::Int::ItemRep.new(item, :default) }
let(:item) { Nanoc::Int::Item.new('some content', {}, '/foo.md') }
describe '#add_filter' do
subject { builder.add_filter(:erb, foo: :bar) }
it 'adds an action' do
expect { subject }
.to change { builder.action_sequence.actions }
.from([])
.to([Nanoc::Int::ProcessingActions::Filter.new(:erb, foo: :bar)])
end
end
describe '#add_layout' do
subject { builder.add_layout('/oink.erb', foo: :bar) }
it 'adds an action' do
expect { subject }
.to change { builder.action_sequence.actions }
.from([])
.to([Nanoc::Int::ProcessingActions::Layout.new('/oink.erb', foo: :bar)])
end
end
describe '#add_snapshot' do
context 'add one snapshot' do
subject { builder.add_snapshot(:last, '/foo.html') }
it 'adds an action' do
expect { subject }
.to change { builder.action_sequence.actions }
.from([])
.to([Nanoc::Int::ProcessingActions::Snapshot.new([:last], ['/foo.html'])])
end
end
context 'add two snapshots with same name' do
subject do
builder.add_snapshot(:last, '/foo.html')
builder.add_snapshot(:last, '/foo.htm')
end
it 'raises' do
expect { subject }
.to raise_error(Nanoc::Int::Errors::CannotCreateMultipleSnapshotsWithSameName, 'Attempted to create a snapshot with a duplicate name :last for the item rep /foo.md (rep name :default)')
end
end
end
end
nanoc-4.11.0/nanoc/spec/nanoc/base/services/compiler/000077500000000000000000000000001340050175000223635ustar00rootroot00000000000000nanoc-4.11.0/nanoc/spec/nanoc/base/services/compiler/phases/000077500000000000000000000000001340050175000236465ustar00rootroot00000000000000nanoc-4.11.0/nanoc/spec/nanoc/base/services/compiler/phases/abstract_spec.rb000066400000000000000000000052271340050175000270160ustar00rootroot00000000000000# frozen_string_literal: true
describe Nanoc::Int::Compiler::Phases::Abstract do
subject(:phase) do
described_class.new(wrapped: wrapped)
end
let(:item) { Nanoc::Int::Item.new('foo', {}, '/stuff.md') }
let(:rep) { Nanoc::Int::ItemRep.new(item, :default) }
let(:wrapped) { nil }
describe '#run' do
subject { phase.run(rep, is_outdated: false) {} }
it 'raises' do
expect { subject }.to raise_error(NotImplementedError)
end
end
describe '#call' do
subject { phase.call(rep, is_outdated: false) }
let(:phase_class) do
Class.new(described_class) do
def self.to_s
'AbstractSpec::MyTestingPhaseClass'
end
def run(_rep, is_outdated:) # rubocop:disable Lint/UnusedMethodArgument
yield
end
end
end
let(:phase) { phase_class.new(wrapped: wrapped) }
let(:wrapped_class) do
Class.new(described_class) do
def self.to_s
'AbstractSpec::MyTestingWrappedPhaseClass'
end
def run(_rep, is_outdated:); end
end
end
let(:wrapped) { wrapped_class.new(wrapped: nil) }
it 'sends the proper notifications' do
expect(Nanoc::Int::NotificationCenter).to receive(:post).with(:phase_started, 'MyTestingPhaseClass', rep).ordered
expect(Nanoc::Int::NotificationCenter).to receive(:post).with(:phase_yielded, 'MyTestingPhaseClass', rep).ordered
expect(Nanoc::Int::NotificationCenter).to receive(:post).with(:phase_started, 'MyTestingWrappedPhaseClass', rep).ordered
expect(Nanoc::Int::NotificationCenter).to receive(:post).with(:phase_ended, 'MyTestingWrappedPhaseClass', rep).ordered
expect(Nanoc::Int::NotificationCenter).to receive(:post).with(:phase_resumed, 'MyTestingPhaseClass', rep).ordered
expect(Nanoc::Int::NotificationCenter).to receive(:post).with(:phase_ended, 'MyTestingPhaseClass', rep).ordered
subject
end
end
describe '#start' do
subject { phase.start }
context 'with wrapped' do
let(:wrapped) { described_class.new(wrapped: nil) }
it 'starts wrapped' do
expect(wrapped).to receive(:start)
subject
end
end
context 'without wrapped' do
let(:wrapped) { nil }
it 'does not start wrapped' do
subject
end
end
end
describe '#stop' do
subject { phase.stop }
context 'with wrapped' do
let(:wrapped) { described_class.new(wrapped: nil) }
it 'stops wrapped' do
expect(wrapped).to receive(:stop)
subject
end
end
context 'without wrapped' do
let(:wrapped) { nil }
it 'does not stop wrapped' do
subject
end
end
end
end
nanoc-4.11.0/nanoc/spec/nanoc/base/services/compiler/phases/cache_spec.rb000066400000000000000000000111361340050175000262520ustar00rootroot00000000000000# frozen_string_literal: true
describe Nanoc::Int::Compiler::Phases::Cache do
subject(:phase) do
described_class.new(
compiled_content_cache: compiled_content_cache,
snapshot_repo: snapshot_repo,
wrapped: wrapped,
)
end
let(:compiled_content_cache) do
Nanoc::Int::CompiledContentCache.new(config: config)
end
let(:snapshot_repo) { Nanoc::Int::SnapshotRepo.new }
let(:wrapped_class) do
Class.new(Nanoc::Int::Compiler::Phases::Abstract) do
def initialize(snapshot_repo)
@snapshot_repo = snapshot_repo
end
def run(rep, is_outdated:) # rubocop:disable Lint/UnusedMethodArgument
@snapshot_repo.set(rep, :last, Nanoc::Int::TextualContent.new('wrapped content'))
end
end
end
let(:wrapped) { wrapped_class.new(snapshot_repo) }
let(:item) { Nanoc::Int::Item.new('item content', {}, '/donkey.md') }
let(:rep) { Nanoc::Int::ItemRep.new(item, :latex) }
let(:config) { Nanoc::Int::Configuration.new(dir: Dir.getwd).with_defaults }
describe '#run' do
subject { phase.call(rep, is_outdated: is_outdated) }
let(:is_outdated) { raise 'override me' }
before do
allow(Nanoc::Int::NotificationCenter).to receive(:post).with(:phase_started, anything, anything)
allow(Nanoc::Int::NotificationCenter).to receive(:post).with(:phase_yielded, anything, anything)
allow(Nanoc::Int::NotificationCenter).to receive(:post).with(:phase_resumed, anything, anything)
allow(Nanoc::Int::NotificationCenter).to receive(:post).with(:phase_ended, anything, anything)
end
shared_examples 'calls wrapped' do
it 'delegates to wrapped' do
expect(wrapped).to receive(:run).with(rep, is_outdated: is_outdated)
subject
end
it 'marks rep as compiled' do
expect { subject }
.to change { rep.compiled? }
.from(false)
.to(true)
end
it 'sends no other notifications' do
subject
end
it 'updates compiled content cache' do
expect { subject }
.to change { compiled_content_cache[rep] }
.from(nil)
.to(last: some_textual_content('wrapped content'))
end
end
context 'outdated' do
let(:is_outdated) { true }
include_examples 'calls wrapped'
end
context 'not outdated' do
let(:is_outdated) { false }
context 'textual cached compiled content available' do
before do
compiled_content_cache[rep] = { last: Nanoc::Int::TextualContent.new('cached') }
end
it 'writes content to cache' do
expect(Nanoc::Int::NotificationCenter).to receive(:post).with(:cached_content_used, rep)
expect { subject }
.to change { snapshot_repo.get(rep, :last) }
.from(nil)
.to(some_textual_content('cached'))
end
it 'marks rep as compiled' do
expect(Nanoc::Int::NotificationCenter).to receive(:post).with(:cached_content_used, rep)
expect { subject }
.to change { rep.compiled? }
.from(false)
.to(true)
end
it 'does not change compiled content cache' do
expect(Nanoc::Int::NotificationCenter).to receive(:post).with(:cached_content_used, rep)
expect { subject }
.not_to change { compiled_content_cache[rep] }
end
end
context 'binary cached compiled content available' do
let(:binary_content) { 'b1n4ry' }
let(:binary_filename) { Tempfile.open('test') { |fn| fn << binary_content }.path }
before do
compiled_content_cache[rep] = { last: Nanoc::Int::BinaryContent.new(binary_filename) }
end
it 'writes content to cache' do
expect { subject }
.to change { snapshot_repo.get(rep, :last) }
.from(nil)
.to(some_textual_content('wrapped content'))
end
it 'marks rep as compiled' do
expect { subject }
.to change { rep.compiled? }
.from(false)
.to(true)
end
it 'changes compiled content cache' do
expect { subject }
.to change { compiled_content_cache[rep] }
.from(last: some_binary_content(binary_content))
.to(last: some_textual_content('wrapped content'))
end
it 'does not send notification' do
expect(Nanoc::Int::NotificationCenter).not_to receive(:post).with(:cached_content_used, rep)
subject
end
end
context 'no cached compiled content available' do
include_examples 'calls wrapped'
end
end
end
end
nanoc-4.11.0/nanoc/spec/nanoc/base/services/compiler/stage_spec.rb000066400000000000000000000013161340050175000250260ustar00rootroot00000000000000# frozen_string_literal: true
describe Nanoc::Int::Compiler::Stage do
subject(:stage) { klass.new }
let(:klass) { described_class }
before { Timecop.freeze(Time.local(2008, 9, 1, 10, 5, 0)) }
after { Timecop.return }
describe '#call' do
subject { stage.call }
it 'raises error' do
expect { subject }.to raise_error(NotImplementedError)
end
context 'actual implementation' do
let(:klass) do
Class.new(described_class) do
def run
Timecop.freeze(Time.now + 13.57)
end
end
end
it 'sends notification' do
expect { subject }
.to send_notification(:stage_ran, 13.57, klass)
end
end
end
end
nanoc-4.11.0/nanoc/spec/nanoc/base/services/compiler/stages/000077500000000000000000000000001340050175000236515ustar00rootroot00000000000000nanoc-4.11.0/nanoc/spec/nanoc/base/services/compiler/stages/calculate_checksums_spec.rb000066400000000000000000000037001340050175000312120ustar00rootroot00000000000000# frozen_string_literal: true
describe Nanoc::Int::Compiler::Stages::CalculateChecksums do
let(:stage) do
described_class.new(items: items, layouts: layouts, code_snippets: code_snippets, config: config)
end
let(:config) do
Nanoc::Int::Configuration.new(dir: Dir.getwd).with_defaults
end
let(:code_snippets) do
[code_snippet]
end
let(:items) do
Nanoc::Int::ItemCollection.new(config, [item])
end
let(:layouts) do
Nanoc::Int::LayoutCollection.new(config, [layout])
end
let(:code_snippet) do
Nanoc::Int::CodeSnippet.new('woof!', 'dog.rb')
end
let(:item) do
Nanoc::Int::Item.new('hello there', {}, '/hi.md')
end
let(:layout) do
Nanoc::Int::Layout.new('t3mpl4t3', {}, '/page.erb')
end
describe '#run' do
subject { stage.run }
it 'checksums items' do
expect(subject.checksum_for(item))
.to eq(Nanoc::Int::Checksummer.calc(item))
expect(subject.content_checksum_for(item))
.to eq(Nanoc::Int::Checksummer.calc_for_content_of(item))
expect(subject.attributes_checksum_for(item))
.to eq(Nanoc::Int::Checksummer.calc_for_each_attribute_of(item))
end
it 'checksums layouts' do
expect(subject.checksum_for(layout))
.to eq(Nanoc::Int::Checksummer.calc(layout))
expect(subject.content_checksum_for(layout))
.to eq(Nanoc::Int::Checksummer.calc_for_content_of(layout))
expect(subject.attributes_checksum_for(layout))
.to eq(Nanoc::Int::Checksummer.calc_for_each_attribute_of(layout))
end
it 'checksums config' do
expect(subject.checksum_for(config))
.to eq(Nanoc::Int::Checksummer.calc(config))
expect(subject.attributes_checksum_for(config))
.to eq(Nanoc::Int::Checksummer.calc_for_each_attribute_of(config))
end
it 'checksums code snippets' do
expect(subject.checksum_for(code_snippet))
.to eq(Nanoc::Int::Checksummer.calc(code_snippet))
end
end
end
nanoc-4.11.0/nanoc/spec/nanoc/base/services/compiler/stages/cleanup_spec.rb000066400000000000000000000051511340050175000266410ustar00rootroot00000000000000# frozen_string_literal: true
describe Nanoc::Int::Compiler::Stages::Cleanup do
let(:stage) { described_class.new(config.output_dirs) }
let(:config) do
Nanoc::Int::Configuration.new(dir: Dir.getwd).with_defaults
end
describe '#run' do
subject { stage.run }
def gen_hash(path)
Digest::SHA1.hexdigest(File.absolute_path(path))[0..12]
end
it 'removes temporary binary items' do
a = Nanoc::Int::TempFilenameFactory.instance.create(Nanoc::Filter::TMP_BINARY_ITEMS_DIR)
File.write(a, 'hello there')
expect { subject }
.to change { File.file?(a) }
.from(true).to(false)
end
it 'removes temporary textual items' do
a = Nanoc::Int::TempFilenameFactory.instance.create(Nanoc::Int::ItemRepWriter::TMP_TEXT_ITEMS_DIR)
File.write(a, 'hello there')
expect { subject }
.to change { File.file?(a) }
.from(true).to(false)
end
shared_examples 'an old store' do
it 'removes the old store' do
FileUtils.mkdir_p('tmp')
File.write('tmp/' + store_name, 'stuff')
expect { subject }
.to change { File.file?('tmp/' + store_name) }
.from(true).to(false)
end
end
context 'tmp/checksums' do
let(:store_name) { 'checksums' }
it_behaves_like 'an old store'
end
context 'tmp/compiled_content' do
let(:store_name) { 'compiled_content' }
it_behaves_like 'an old store'
end
context 'tmp/dependencies' do
let(:store_name) { 'dependencies' }
it_behaves_like 'an old store'
end
context 'tmp/outdatedness' do
let(:store_name) { 'outdatedness' }
it_behaves_like 'an old store'
end
context 'tmp/action_sequence' do
let(:store_name) { 'action_sequence' }
it_behaves_like 'an old store'
end
context 'tmp/somethingelse' do
it 'does not removes the store' do
FileUtils.mkdir_p('tmp')
File.write('tmp/somethingelse', 'stuff')
expect { subject }
.not_to change { File.file?('tmp/somethingelse') }
end
end
it 'removes stores for unused output paths' do
default_dir = "tmp/nanoc/#{gen_hash(Dir.getwd + '/output')}"
prod_dir = "tmp/nanoc/#{gen_hash(Dir.getwd + '/output_production')}"
staging_dir = "tmp/nanoc/#{gen_hash(Dir.getwd + '/output_staging')}"
FileUtils.mkdir_p(default_dir)
FileUtils.mkdir_p(prod_dir)
FileUtils.mkdir_p(staging_dir)
expect { subject }
.to change { Dir.glob('tmp/nanoc/*').sort }
.from([default_dir, prod_dir, staging_dir].sort)
.to([default_dir])
end
end
end
nanoc-4.11.0/nanoc/spec/nanoc/base/services/compiler/stages/compile_reps_spec.rb000066400000000000000000000112311340050175000276670ustar00rootroot00000000000000# frozen_string_literal: true
describe Nanoc::Int::Compiler::Stages::CompileReps do
let(:stage) do
described_class.new(
reps: reps,
outdatedness_store: outdatedness_store,
dependency_store: dependency_store,
action_sequences: action_sequences,
compilation_context: compilation_context,
compiled_content_cache: compiled_content_cache,
)
end
let(:compilation_context) do
Nanoc::Int::CompilationContext.new(
action_provider: action_provider,
reps: reps,
site: site,
compiled_content_cache: compiled_content_cache,
snapshot_repo: snapshot_repo,
)
end
let(:action_provider) { double(:action_provider) }
let(:action_sequences) { double(:action_sequences) }
let(:reps) { Nanoc::Int::ItemRepRepo.new }
let(:compiled_content_cache) { Nanoc::Int::CompiledContentCache.new(config: config) }
let(:snapshot_repo) { Nanoc::Int::SnapshotRepo.new }
let(:outdatedness_store) { Nanoc::Int::OutdatednessStore.new(config: config) }
let(:dependency_store) { Nanoc::Int::DependencyStore.new(items, layouts, config) }
let(:rep) { Nanoc::Int::ItemRep.new(item, :default) }
let(:item) { Nanoc::Int::Item.new('<%= 1 + 2 %>', {}, '/hi.md') }
let(:other_rep) { Nanoc::Int::ItemRep.new(other_item, :default) }
let(:other_item) { Nanoc::Int::Item.new('other content', {}, '/other.md') }
let(:site) do
Nanoc::Int::Site.new(
config: config,
code_snippets: code_snippets,
data_source: Nanoc::Int::InMemDataSource.new(items, layouts),
)
end
let(:config) { Nanoc::Int::Configuration.new(dir: Dir.getwd).with_defaults }
let(:code_snippets) { [] }
let(:layouts) do
Nanoc::Int::LayoutCollection.new(config)
end
let(:items) do
Nanoc::Int::ItemCollection.new(
config,
[item, other_item],
)
end
let(:memory) do
actions =
[
Nanoc::Int::ProcessingActions::Filter.new(:erb, {}),
Nanoc::Int::ProcessingActions::Snapshot.new([:last], []),
]
Nanoc::Int::ActionSequence.new(nil, actions: actions)
end
before do
reps << rep
reps << other_rep
reps.each do |rep|
rep.snapshot_defs << Nanoc::Int::SnapshotDef.new(:last, binary: false)
end
allow(action_sequences).to receive(:[]).with(rep).and_return(memory)
allow(action_sequences).to receive(:[]).with(other_rep).and_return(memory)
end
describe '#compile_reps' do
subject { stage.run }
let(:snapshot_defs_for_rep) do
[Nanoc::Int::SnapshotDef.new(:last, binary: false)]
end
let(:snapshot_defs_for_other_rep) do
[Nanoc::Int::SnapshotDef.new(:last, binary: false)]
end
context 'rep not in outdatedness store' do
before do
# Needed for consistency
compiled_content_cache[rep] = { last: Nanoc::Int::TextualContent.new('asdf') }
compiled_content_cache[other_rep] = { last: Nanoc::Int::TextualContent.new('asdf') }
end
it 'keeps the item rep out of the outdatedness store' do
expect(outdatedness_store.include?(rep)).not_to be
expect { subject }.not_to change { outdatedness_store.include?(rep) }
end
end
context 'rep in outdatedness store' do
before { outdatedness_store.add(rep) }
before do
# Needed for consistency
compiled_content_cache[other_rep] = { last: Nanoc::Int::TextualContent.new('asdf') }
end
it 'compiles individual reps' do
expect { subject }.to change { snapshot_repo.get(rep, :last) }
.from(nil)
.to(some_textual_content('3'))
end
it 'removes the item rep from the outdatedness store' do
expect { subject }.to change { outdatedness_store.include?(rep) }.from(true).to(false)
end
context 'exception' do
let(:item) { Nanoc::Int::Item.new('<%= \'invalid_ruby %>', {}, '/hi.md') }
it 'wraps exception' do
expect { subject }.to raise_error(Nanoc::Int::Errors::CompilationError)
end
it 'contains the right item rep in the wrapped exception' do
expect { subject }.to raise_error do |err|
expect(err.item_rep).to eql(rep)
end
end
it 'contains the right wrapped exception' do
expect { subject }.to raise_error do |err|
expect(err.unwrap).to be_a(SyntaxError)
expect(err.unwrap.message).to start_with('item /hi.md (rep default):1: unterminated string meets end of file')
end
end
it 'keeps the item rep in the outdatedness store' do
expect(outdatedness_store.include?(rep)).to be
expect { subject rescue nil }.not_to change { outdatedness_store.include?(rep) }
end
end
end
end
end
nanoc-4.11.0/nanoc/spec/nanoc/base/services/compiler/stages/determine_outdatedness_spec.rb000066400000000000000000000070271340050175000317540ustar00rootroot00000000000000# frozen_string_literal: true
describe Nanoc::Int::Compiler::Stages::DetermineOutdatedness do
let(:stage) do
described_class.new(
reps: reps,
outdatedness_checker: outdatedness_checker,
outdatedness_store: outdatedness_store,
)
end
let(:reps) do
Nanoc::Int::ItemRepRepo.new
end
let(:outdatedness_checker) do
double(:outdatedness_checker)
end
let(:outdatedness_store) do
Nanoc::Int::OutdatednessStore.new(config: config)
end
let(:config) { Nanoc::Int::Configuration.new(dir: Dir.getwd).with_defaults }
let(:code_snippets) { [] }
describe '#run' do
subject { stage.run }
context 'outdatedness store is empty' do
let(:item) do
Nanoc::Int::Item.new('', {}, '/hi.md')
end
let(:rep) do
Nanoc::Int::ItemRep.new(item, :woof)
end
let(:other_rep) do
Nanoc::Int::ItemRep.new(item, :bark)
end
context 'outdatedness checker thinks rep is outdated' do
before do
reps << rep
reps << other_rep
expect(outdatedness_checker)
.to receive(:outdated?).with(rep).and_return(true)
expect(outdatedness_checker)
.to receive(:outdated?).with(other_rep).and_return(false)
end
it 'adds the rep' do
expect { subject }
.to change { outdatedness_store.include?(rep) }
.from(false)
.to(true)
end
it 'also adds the other rep' do
expect { subject }
.to change { outdatedness_store.include?(other_rep) }
.from(false)
.to(true)
end
it 'returns a list with the known rep’s item' do
expect(subject).to eq([rep.item])
end
end
context 'outdatedness checker thinks rep is not outdated' do
it 'keeps the outdatedness store empty' do
expect { subject }
.not_to change { outdatedness_store.empty? }
end
it 'returns an empty list' do
expect(subject).to be_empty
end
end
end
context 'outdatedness store contains known rep' do
let(:item) do
Nanoc::Int::Item.new('', {}, '/hi.md')
end
let(:rep) do
Nanoc::Int::ItemRep.new(item, :woof)
end
let(:other_rep) do
Nanoc::Int::ItemRep.new(item, :bark)
end
before do
reps << rep
reps << other_rep
outdatedness_store.add(rep)
expect(outdatedness_checker)
.to receive(:outdated?).with(other_rep).and_return(false)
end
it 'keeps the rep' do
expect { subject }
.not_to change { outdatedness_store.include?(rep) }
end
it 'also adds the other rep' do
expect { subject }
.to change { outdatedness_store.include?(other_rep) }
.from(false)
.to(true)
end
it 'returns a list with the known rep’s item' do
expect(subject).to eq([rep.item])
end
end
context 'outdatedness store contains unknown rep' do
let(:item) do
Nanoc::Int::Item.new('', {}, '/hi.md')
end
let(:unknown_rep) do
Nanoc::Int::ItemRep.new(item, :woof)
end
before do
outdatedness_store.add(unknown_rep)
end
it 'removes the unknown rep' do
expect { subject }
.to change { outdatedness_store.include?(unknown_rep) }
.from(true)
.to(false)
end
it 'returns an empty list' do
expect(subject).to be_empty
end
end
end
end
nanoc-4.11.0/nanoc/spec/nanoc/base/services/compiler/stages/preprocess_spec.rb000066400000000000000000000055521340050175000274040ustar00rootroot00000000000000# frozen_string_literal: true
describe Nanoc::Int::Compiler::Stages::Preprocess do
let(:stage) do
described_class.new(
action_provider: action_provider,
site: site,
dependency_store: dependency_store,
checksum_store: checksum_store,
)
end
let(:action_provider) do
double(:action_provider)
end
let(:site) do
Nanoc::Int::Site.new(
config: config,
code_snippets: [],
data_source: data_source,
)
end
let(:data_source) { Nanoc::Int::InMemDataSource.new(items, layouts) }
let(:config) { Nanoc::Int::Configuration.new(dir: Dir.getwd).with_defaults }
let(:items) { Nanoc::Int::ItemCollection.new(config) }
let(:layouts) { Nanoc::Int::LayoutCollection.new(config) }
let(:dependency_store) do
Nanoc::Int::DependencyStore.new(items, layouts, config)
end
let(:checksum_store) do
Nanoc::Int::ChecksumStore.new(config: config, objects: items.to_a + layouts.to_a)
end
describe '#run' do
subject { stage.run }
context 'no preprocessing needed' do
before do
expect(action_provider).to receive(:need_preprocessing?).and_return(false)
end
it 'marks the site as preprocessed' do
expect { subject }
.to change { site.preprocessed? }
.from(false)
.to(true)
end
it 'freezes the site' do
subject
end
end
context 'preprocessing needed' do
let(:new_item) { Nanoc::Int::Item.new('new item', {}, '/new.md') }
let(:new_layout) { Nanoc::Int::Layout.new('new layout', {}, '/new.md') }
before do
expect(action_provider).to receive(:need_preprocessing?).and_return(true)
expect(action_provider).to receive(:preprocess) do |site|
site.data_source =
Nanoc::Int::InMemDataSource.new(
Nanoc::Int::ItemCollection.new(config, [new_item]),
Nanoc::Int::LayoutCollection.new(config, [new_layout]),
)
end
end
it 'marks the site as preprocessed' do
expect { subject }
.to change { site.preprocessed? }
.from(false)
.to(true)
end
it 'freezes the site' do
expect { subject }
.to change { site.config.frozen? }
.from(false)
.to(true)
end
it 'sets items on dependency store' do
expect { subject }
.to change { dependency_store.items.to_a }
.from([])
.to([new_item])
end
it 'sets layouts on dependency store' do
expect { subject }
.to change { dependency_store.layouts.to_a }
.from([])
.to([new_layout])
end
it 'sets data on checksum store' do
expect { subject }
.to change { checksum_store.objects.to_a }
.from([])
.to(match_array([new_item, new_layout, config]))
end
end
end
end
nanoc-4.11.0/nanoc/spec/nanoc/base/services/dependency_tracker_spec.rb000066400000000000000000000162661340050175000257540ustar00rootroot00000000000000# frozen_string_literal: true
describe Nanoc::Int::DependencyTracker do
let(:tracker) { described_class.new(store) }
let(:store) { Nanoc::Int::DependencyStore.new(empty_items, empty_layouts, config) }
let(:item_a) { Nanoc::Int::Item.new('a', {}, '/a.md') }
let(:item_b) { Nanoc::Int::Item.new('b', {}, '/b.md') }
let(:item_c) { Nanoc::Int::Item.new('c', {}, '/c.md') }
let(:empty_items) { Nanoc::Int::ItemCollection.new(config) }
let(:empty_layouts) { Nanoc::Int::LayoutCollection.new(config) }
let(:config) { Nanoc::Int::Configuration.new(dir: Dir.getwd).with_defaults }
shared_examples 'a null dependency tracker' do
let(:tracker) { Nanoc::Int::DependencyTracker::Null.new }
example do
expect { subject }.not_to change { store.objects_causing_outdatedness_of(item_a) }
end
example do
expect { subject }.not_to change { store.objects_causing_outdatedness_of(item_b) }
end
example do
expect { subject }.not_to change { store.objects_causing_outdatedness_of(item_c) }
end
example do
expect { subject }.not_to change { store.dependencies_causing_outdatedness_of(item_a) }
end
example do
expect { subject }.not_to change { store.dependencies_causing_outdatedness_of(item_b) }
end
example do
expect { subject }.not_to change { store.dependencies_causing_outdatedness_of(item_c) }
end
end
describe '#enter and #exit' do
context 'enter' do
subject do
tracker.enter(item_a)
end
it_behaves_like 'a null dependency tracker'
example do
expect { subject }.not_to change { store.objects_causing_outdatedness_of(item_a) }
end
example do
expect { subject }.not_to change { store.objects_causing_outdatedness_of(item_b) }
end
example do
expect { subject }.not_to change { store.objects_causing_outdatedness_of(item_c) }
end
end
context 'enter + enter' do
subject do
tracker.enter(item_a)
tracker.enter(item_b)
end
it_behaves_like 'a null dependency tracker'
it 'changes predecessors of item A' do
expect { subject }.to change { store.objects_causing_outdatedness_of(item_a) }
.from([]).to([item_b])
end
example do
expect { subject }.not_to change { store.objects_causing_outdatedness_of(item_b) }
end
example do
expect { subject }.not_to change { store.objects_causing_outdatedness_of(item_c) }
end
end
context 'enter + enter with props' do
subject do
tracker.enter(item_a)
tracker.enter(item_b, compiled_content: true)
end
it_behaves_like 'a null dependency tracker'
it 'changes predecessors of item A' do
expect { subject }.to change { store.objects_causing_outdatedness_of(item_a) }
.from([]).to([item_b])
end
it 'changes dependencies causing outdatedness of item A' do
expect { subject }.to change { store.dependencies_causing_outdatedness_of(item_a).size }
.from(0).to(1)
end
it 'creates correct new dependency causing outdatedness of item A' do
subject
dep = store.dependencies_causing_outdatedness_of(item_a)[0]
expect(dep.from).to eql(item_b)
expect(dep.to).to eql(item_a)
end
it 'creates dependency with correct props causing outdatedness of item A' do
subject
dep = store.dependencies_causing_outdatedness_of(item_a)[0]
expect(dep.props.compiled_content?).to eq(true)
expect(dep.props.raw_content?).to eq(false)
expect(dep.props.attributes?).to eq(false)
expect(dep.props.path?).to eq(false)
end
example do
expect { subject }.not_to change { store.objects_causing_outdatedness_of(item_b) }
end
example do
expect { subject }.not_to change { store.objects_causing_outdatedness_of(item_c) }
end
example do
expect { subject }.not_to change { store.dependencies_causing_outdatedness_of(item_b) }
end
example do
expect { subject }.not_to change { store.dependencies_causing_outdatedness_of(item_c) }
end
end
context 'enter + enter with prop + exit + enter with prop' do
subject do
tracker.enter(item_a)
tracker.enter(item_b, compiled_content: true)
tracker.exit
tracker.enter(item_b, attributes: true)
end
it_behaves_like 'a null dependency tracker'
it 'changes predecessors of item A' do
expect { subject }.to change { store.objects_causing_outdatedness_of(item_a) }
.from([]).to([item_b])
end
it 'changes dependencies causing outdatedness of item A' do
expect { subject }.to change { store.dependencies_causing_outdatedness_of(item_a).size }
.from(0).to(1)
end
it 'creates correct new dependency causing outdatedness of item A' do
subject
dep = store.dependencies_causing_outdatedness_of(item_a)[0]
expect(dep.from).to eql(item_b)
expect(dep.to).to eql(item_a)
end
it 'creates dependency with correct props causing outdatedness of item A' do
subject
dep = store.dependencies_causing_outdatedness_of(item_a)[0]
expect(dep.props.compiled_content?).to eq(true)
expect(dep.props.attributes?).to eq(true)
expect(dep.props.raw_content?).to eq(false)
expect(dep.props.path?).to eq(false)
end
example do
expect { subject }.not_to change { store.objects_causing_outdatedness_of(item_b) }
end
example do
expect { subject }.not_to change { store.objects_causing_outdatedness_of(item_c) }
end
example do
expect { subject }.not_to change { store.dependencies_causing_outdatedness_of(item_b) }
end
example do
expect { subject }.not_to change { store.dependencies_causing_outdatedness_of(item_c) }
end
end
context 'enter + enter + exit + enter' do
subject do
tracker.enter(item_a)
tracker.enter(item_b)
tracker.exit
tracker.enter(item_c)
end
it_behaves_like 'a null dependency tracker'
it 'changes predecessors of item A' do
expect { subject }.to change { store.objects_causing_outdatedness_of(item_a) }
.from([]).to([item_b, item_c])
end
example do
expect { subject }.not_to change { store.objects_causing_outdatedness_of(item_b) }
end
example do
expect { subject }.not_to change { store.objects_causing_outdatedness_of(item_c) }
end
end
context 'enter + bounce + enter' do
subject do
tracker.enter(item_a)
tracker.bounce(item_b)
tracker.enter(item_c)
end
it_behaves_like 'a null dependency tracker'
it 'changes predecessors of item A' do
expect { subject }.to change { store.objects_causing_outdatedness_of(item_a) }
.from([]).to([item_b, item_c])
end
example do
expect { subject }.not_to change { store.objects_causing_outdatedness_of(item_b) }
end
example do
expect { subject }.not_to change { store.objects_causing_outdatedness_of(item_c) }
end
end
end
end
nanoc-4.11.0/nanoc/spec/nanoc/base/services/executor_spec.rb000066400000000000000000000515201340050175000237510ustar00rootroot00000000000000# frozen_string_literal: true
describe Nanoc::Int::Executor do
let(:executor) { described_class.new(rep, compilation_context, dependency_tracker) }
let(:compilation_context) do
Nanoc::Int::CompilationContext.new(
action_provider: action_provider,
reps: reps,
site: site,
compiled_content_cache: compiled_content_cache,
snapshot_repo: snapshot_repo,
)
end
let(:item) { Nanoc::Int::Item.new(content, {}, '/index.md') }
let(:rep) { Nanoc::Int::ItemRep.new(item, :donkey) }
let(:content) { Nanoc::Int::TextualContent.new('Donkey Power').tap(&:freeze) }
let(:action_provider) { double(:action_provider) }
let(:reps) { double(:reps) }
let(:site) { double(:site) }
let(:compiled_content_cache) { double(:compiled_content_cache) }
let(:snapshot_repo) { Nanoc::Int::SnapshotRepo.new }
let(:dependency_tracker) { Nanoc::Int::DependencyTracker.new(double(:dependency_store)) }
describe '#filter' do
let(:assigns) { {} }
let(:content) { Nanoc::Int::TextualContent.new('<%= "Donkey" %> Power') }
before do
allow(compilation_context).to receive(:assigns_for) { assigns }
end
context 'normal flow with textual rep' do
subject { executor.filter(:erb) }
before do
expect(Nanoc::Int::NotificationCenter)
.to receive(:post).with(:filtering_started, rep, :erb)
expect(Nanoc::Int::NotificationCenter)
.to receive(:post).with(:filtering_ended, rep, :erb)
snapshot_repo.set(rep, :last, content)
end
it 'does not set :pre on rep' do
expect(snapshot_repo.get(rep, :pre)).to be_nil
expect { subject }.not_to change { snapshot_repo.get(rep, :pre) }
end
it 'does not set :post on rep' do
expect(snapshot_repo.get(rep, :post)).to be_nil
expect { subject }.not_to change { snapshot_repo.get(rep, :post) }
end
it 'updates :last on rep' do
expect { subject }
.to change { snapshot_repo.get(rep, :last).string }
.from('<%= "Donkey" %> Power')
.to('Donkey Power')
end
it 'does not set :pre in repo' do
expect(snapshot_repo.get(rep, :pre)).to be_nil
expect { subject }.not_to change { snapshot_repo.get(rep, :pre) }
end
it 'does not set :post in repo' do
expect(snapshot_repo.get(rep, :post)).to be_nil
expect { subject }.not_to change { snapshot_repo.get(rep, :post) }
end
it 'updates :last in repo' do
expect { subject }
.to change { snapshot_repo.get(rep, :last).string }
.from('<%= "Donkey" %> Power')
.to('Donkey Power')
end
it 'returns frozen data' do
executor.filter(:erb)
expect(snapshot_repo.get(rep, :last)).to be_frozen
end
end
context 'normal flow with binary rep' do
subject { executor.filter(:whatever) }
let(:content) { Nanoc::Int::BinaryContent.new(File.expand_path('foo.dat')) }
before do
expect(Nanoc::Int::NotificationCenter)
.to receive(:post).with(:filtering_started, rep, :whatever)
expect(Nanoc::Int::NotificationCenter)
.to receive(:post).with(:filtering_ended, rep, :whatever)
File.write(content.filename, 'Foo Data')
filter_class = Class.new(::Nanoc::Filter) do
type :binary
def run(filename, _params = {})
File.write(output_filename, "Compiled data for #{filename}")
end
end
expect(Nanoc::Filter).to receive(:named).with(:whatever) { filter_class }
snapshot_repo.set(rep, :last, content)
end
it 'does not set :pre on rep' do
expect(snapshot_repo.get(rep, :pre)).to be_nil
expect { subject }.not_to change { snapshot_repo.get(rep, :pre) }
end
it 'does not set :post on rep' do
expect(snapshot_repo.get(rep, :post)).to be_nil
expect { subject }.not_to change { snapshot_repo.get(rep, :post) }
end
it 'updates :last on rep' do
expect { subject }
.to change { snapshot_repo.get(rep, :last) }
.from(some_binary_content('Foo Data'))
.to(some_binary_content(/\ACompiled data for (C:)?\/.*\/foo.dat\z/))
end
it 'does not set :pre in repo' do
expect(snapshot_repo.get(rep, :pre)).to be_nil
expect { subject }.not_to change { snapshot_repo.get(rep, :pre) }
end
it 'does not set :post in repo' do
expect(snapshot_repo.get(rep, :post)).to be_nil
expect { subject }.not_to change { snapshot_repo.get(rep, :post) }
end
it 'updates :last in repo' do
expect { subject }
.to change { File.read(snapshot_repo.get(rep, :last).filename) }
.from('Foo Data')
.to(/\ACompiled data for (C:)?\/.*\/foo.dat\z/)
end
it 'returns frozen data' do
executor.filter(:whatever)
expect(snapshot_repo.get(rep, :last)).to be_frozen
end
end
context 'normal flow with binary rep and binary-to-text filter' do
subject { executor.filter(:whatever) }
let(:content) { Nanoc::Int::BinaryContent.new(File.expand_path('foo.dat')) }
before do
expect(Nanoc::Int::NotificationCenter)
.to receive(:post).with(:filtering_started, rep, :whatever)
expect(Nanoc::Int::NotificationCenter)
.to receive(:post).with(:filtering_ended, rep, :whatever)
File.write(content.filename, 'Foo Data')
filter_class = Class.new(::Nanoc::Filter) do
type binary: :text
def run(filename, _params = {})
"Compiled data for #{filename}"
end
end
expect(Nanoc::Filter).to receive(:named).with(:whatever) { filter_class }
snapshot_repo.set(rep, :last, content)
end
it 'does not set :pre on rep' do
expect(snapshot_repo.get(rep, :pre)).to be_nil
expect { subject }.not_to change { snapshot_repo.get(rep, :pre) }
end
it 'does not set :post on rep' do
expect(snapshot_repo.get(rep, :post)).to be_nil
expect { subject }.not_to change { snapshot_repo.get(rep, :post) }
end
it 'updates :last on rep' do
expect { subject }
.to change { snapshot_repo.get(rep, :last) }
.from(some_binary_content('Foo Data'))
.to(some_textual_content(/\ACompiled data for (C:)?\/.*\/foo.dat\z/))
end
it 'does not set :pre in repo' do
expect(snapshot_repo.get(rep, :pre)).to be_nil
expect { subject }.not_to change { snapshot_repo.get(rep, :pre) }
end
it 'does not set :post in repo' do
expect(snapshot_repo.get(rep, :post)).to be_nil
expect { subject }.not_to change { snapshot_repo.get(rep, :post) }
end
it 'updates :last in repo' do
expect { subject }
.to change { snapshot_repo.get(rep, :last) }
.from(some_binary_content('Foo Data'))
.to(some_textual_content(/\ACompiled data for (C:)?\/.*\/foo.dat\z/))
end
end
context 'normal flow with textual rep and text-to-binary filter' do
subject { executor.filter(:whatever) }
before do
expect(Nanoc::Int::NotificationCenter)
.to receive(:post).with(:filtering_started, rep, :whatever)
expect(Nanoc::Int::NotificationCenter)
.to receive(:post).with(:filtering_ended, rep, :whatever)
filter_class = Class.new(::Nanoc::Filter) do
type text: :binary
def run(content, _params = {})
File.write(output_filename, "Binary #{content}")
end
end
expect(Nanoc::Filter).to receive(:named).with(:whatever) { filter_class }
snapshot_repo.set(rep, :last, content)
end
it 'does not set :pre on rep' do
expect(snapshot_repo.get(rep, :pre)).to be_nil
expect { subject }.not_to change { snapshot_repo.get(rep, :pre) }
end
it 'does not set :post on rep' do
expect(snapshot_repo.get(rep, :post)).to be_nil
expect { subject }.not_to change { snapshot_repo.get(rep, :post) }
end
it 'updates :last on rep' do
expect { subject }
.to change { snapshot_repo.get(rep, :last) }
.from(some_textual_content('<%= "Donkey" %> Power'))
.to(some_binary_content('Binary <%= "Donkey" %> Power'))
end
it 'does not set :pre in repo' do
expect(snapshot_repo.get(rep, :pre)).to be_nil
expect { subject }.not_to change { snapshot_repo.get(rep, :pre) }
end
it 'does not set :post in repo' do
expect(snapshot_repo.get(rep, :post)).to be_nil
expect { subject }.not_to change { snapshot_repo.get(rep, :post) }
end
it 'updates :last in repo' do
expect { subject }
.to change { snapshot_repo.get(rep, :last) }
.from(some_textual_content('<%= "Donkey" %> Power'))
.to(some_binary_content('Binary <%= "Donkey" %> Power'))
end
end
context 'non-existant filter' do
it 'raises' do
expect { executor.filter(:ajlsdfjklaskldfj) }
.to raise_error(Nanoc::Int::Errors::UnknownFilter)
end
end
context 'non-binary rep, binary-to-something filter' do
before do
filter_class = Class.new(::Nanoc::Filter) do
type :binary
def run(_content, _params = {}); end
end
expect(Nanoc::Filter).to receive(:named).with(:whatever) { filter_class }
snapshot_repo.set(rep, :last, content)
end
it 'raises' do
expect { executor.filter(:whatever) }
.to raise_error(Nanoc::Int::Errors::CannotUseBinaryFilter)
end
end
context 'binary rep, text-to-something filter' do
let(:content) { Nanoc::Int::BinaryContent.new(File.expand_path('foo.md')) }
before do
snapshot_repo.set(rep, :last, content)
end
it 'raises' do
expect { executor.filter(:erb) }
.to raise_error(Nanoc::Int::Errors::CannotUseTextualFilter)
end
end
context 'binary filter that does not write anything' do
let(:content) { Nanoc::Int::BinaryContent.new(File.expand_path('foo.dat')) }
before do
expect(Nanoc::Int::NotificationCenter)
.to receive(:post).with(:filtering_started, rep, :whatever)
expect(Nanoc::Int::NotificationCenter)
.to receive(:post).with(:filtering_ended, rep, :whatever)
File.write(content.filename, 'Foo Data')
filter_class = Class.new(::Nanoc::Filter) do
type :binary
def run(_filename, _params = {}); end
end
snapshot_repo.set(rep, :last, content)
expect(Nanoc::Filter).to receive(:named).with(:whatever) { filter_class }
end
example do
expect { executor.filter(:whatever) }
.to raise_error(Nanoc::Int::Errors::OutputNotWritten)
end
end
context 'content is frozen' do
before do
snapshot_repo.set(rep, :last, item.content)
end
let(:item) do
Nanoc::Int::Item.new('foo bar', {}, '/foo.md').tap(&:freeze)
end
let(:filter_that_modifies_content) do
Class.new(::Nanoc::Filter) do
def run(content, _params = {})
content.gsub!('foo', 'moo')
content
end
end
end
let(:filter_that_modifies_params) do
Class.new(::Nanoc::Filter) do
def run(_content, params = {})
params[:foo] = 'bar'
'asdf'
end
end
end
it 'errors when attempting to modify content' do
expect(Nanoc::Filter).to receive(:named).with(:whatever).and_return(filter_that_modifies_content)
expect { executor.filter(:whatever) }.to raise_frozen_error
end
it 'receives frozen filter args' do
expect(Nanoc::Filter).to receive(:named).with(:whatever).and_return(filter_that_modifies_params)
expect { executor.filter(:whatever) }.to raise_frozen_error
end
end
end
describe '#layout' do
let(:site) { double(:site, config: config, layouts: layouts) }
let(:config) do
{
string_pattern_type: 'glob',
}
end
let(:layout) do
Nanoc::Int::Layout.new(layout_content, { bug: 'Gum Emperor' }, '/default.erb')
end
let(:layouts) { [layout] }
let(:layout_content) { 'head <%= @foo %> foot' }
let(:assigns) do
{ foo: 'hallo' }
end
let(:view_context) do
Nanoc::ViewContextForCompilation.new(
reps: Nanoc::Int::ItemRepRepo.new,
items: Nanoc::Int::ItemCollection.new(config),
dependency_tracker: dependency_tracker,
compilation_context: double(:compilation_context),
snapshot_repo: snapshot_repo,
)
end
let(:action_sequence) do
Nanoc::Int::ActionSequence.build(rep) do |b|
b.add_filter(:erb, {})
end
end
before do
rep.snapshot_defs = [Nanoc::Int::SnapshotDef.new(:pre, binary: false)]
snapshot_repo.set(rep, :last, content)
allow(compilation_context).to receive(:site) { site }
allow(compilation_context).to receive(:assigns_for).with(rep, dependency_tracker) { assigns }
allow(compilation_context).to receive(:create_view_context).with(dependency_tracker).and_return(view_context)
allow(action_provider).to receive(:action_sequence_for).with(layout).and_return(action_sequence)
end
subject { executor.layout('/default.*') }
context 'accessing layout attributes' do
let(:layout_content) { 'head <%= @layout[:bug] %> foot' }
it 'exposes @layout as view' do
allow(dependency_tracker).to receive(:enter)
.with(layout, raw_content: true, attributes: false, compiled_content: false, path: false)
allow(dependency_tracker).to receive(:enter)
.with(layout, raw_content: false, attributes: [:bug], compiled_content: false, path: false)
allow(dependency_tracker).to receive(:exit)
subject
expect(snapshot_repo.get(rep, :last).string).to eq('head Gum Emperor foot')
end
end
context 'normal flow' do
it 'updates :last on rep' do
expect { subject }
.to change { snapshot_repo.get(rep, :last) }
.from(some_textual_content('Donkey Power'))
.to(some_textual_content('head hallo foot'))
end
it 'updates :last in repo' do
expect { subject }
.to change { snapshot_repo.get(rep, :last) }
.from(some_textual_content('Donkey Power'))
.to(some_textual_content('head hallo foot'))
end
it 'sets frozen content' do
subject
expect(snapshot_repo.get(rep, :last)).to be_frozen
expect(snapshot_repo.get(rep, :pre)).to be_frozen
end
it 'does not create pre snapshot' do
# a #layout is followed by a #snapshot(:pre, …)
expect(snapshot_repo.get(rep, :pre)).to be_nil
subject
expect(snapshot_repo.get(rep, :pre)).to be_nil
end
it 'sends notifications' do
expect(Nanoc::Int::NotificationCenter).to receive(:post).with(:filtering_started, rep, :erb).ordered
expect(Nanoc::Int::NotificationCenter).to receive(:post).with(:filtering_ended, rep, :erb).ordered
subject
end
context 'compiled_content reference in layout' do
let(:layout_content) { 'head <%= @item_rep.compiled_content(snapshot: :pre) %> foot' }
let(:assigns) do
{ item_rep: Nanoc::CompilationItemRepView.new(rep, view_context) }
end
before do
executor.snapshot(:pre)
end
it 'updates :last on rep' do
expect { subject }
.to change { snapshot_repo.get(rep, :last) }
.from(some_textual_content('Donkey Power'))
.to(some_textual_content('head Donkey Power foot'))
end
it 'updates :last in repo' do
expect { subject }
.to change { snapshot_repo.get(rep, :last) }
.from(some_textual_content('Donkey Power'))
.to(some_textual_content('head Donkey Power foot'))
end
end
context 'content with layout reference' do
let(:layout_content) { 'head <%= @layout.identifier %> foot' }
it 'updates :last on rep' do
expect { subject }
.to change { snapshot_repo.get(rep, :last) }
.from(some_textual_content('Donkey Power'))
.to(some_textual_content('head /default.erb foot'))
end
it 'updates :last in repo' do
expect { subject }
.to change { snapshot_repo.get(rep, :last) }
.from(some_textual_content('Donkey Power'))
.to(some_textual_content('head /default.erb foot'))
end
end
end
context 'no layout found' do
let(:layouts) do
[Nanoc::Int::Layout.new('head <%= @foo %> foot', {}, '/other.erb')]
end
it 'raises' do
expect { subject }.to raise_error(Nanoc::Int::Errors::UnknownLayout)
end
end
context 'no filter specified' do
let(:action_sequence) do
Nanoc::Int::ActionSequence.new(rep)
end
it 'raises' do
expect { subject }.to raise_error(Nanoc::Int::Errors::UndefinedFilterForLayout)
end
end
context 'binary item' do
let(:content) { Nanoc::Int::BinaryContent.new(File.expand_path('donkey.md')) }
it 'raises' do
expect { subject }.to raise_error(
Nanoc::Int::Errors::CannotLayoutBinaryItem,
'The “/index.md” item (rep “donkey”) cannot be laid out because it is a binary item. If you are getting this error for an item that should be textual instead of binary, make sure that its extension is included in the text_extensions array in the site configuration.',
)
end
end
it 'receives frozen filter args' do
filter_class = Class.new(::Nanoc::Filter) do
def run(_content, params = {})
params[:foo] = 'bar'
'asdf'
end
end
expect(Nanoc::Filter).to receive(:named).with(:erb) { filter_class }
expect { subject }.to raise_frozen_error
end
end
describe '#snapshot' do
subject { executor.snapshot(:something) }
before do
snapshot_repo.set(rep, :last, content)
File.write('donkey.dat', 'binary donkey')
end
context 'binary content' do
let(:content) { Nanoc::Int::BinaryContent.new(File.expand_path('donkey.dat')) }
it 'creates snapshots on rep' do
expect { subject }
.to change { snapshot_repo.get(rep, :something) }
.from(nil)
.to(some_binary_content('binary donkey'))
end
it 'creates snapshots in repo' do
expect { subject }
.to change { snapshot_repo.get(rep, :something) }
.from(nil)
.to(some_binary_content('binary donkey'))
end
end
context 'textual content' do
let(:content) { Nanoc::Int::TextualContent.new('Donkey Power') }
it 'creates snapshots on rep' do
expect { subject }
.to change { snapshot_repo.get(rep, :something) }
.from(nil)
.to(some_textual_content('Donkey Power'))
end
it 'creates snapshots in repo' do
expect { subject }
.to change { snapshot_repo.get(rep, :something) }
.from(nil)
.to(some_textual_content('Donkey Power'))
end
end
context 'final snapshot' do
let(:content) { Nanoc::Int::TextualContent.new('Donkey Power') }
context 'raw path' do
before do
rep.raw_paths = { something: [Dir.getwd + '/output/donkey.md'] }
end
it 'does not write' do
executor.snapshot(:something)
expect(File.file?('output/donkey.md')).not_to be
end
end
context 'no raw path' do
it 'does not write' do
executor.snapshot(:something)
expect(File.file?('output/donkey.md')).to eq(false)
end
end
end
end
describe '#find_layout' do
let(:site) { double(:site, config: config, layouts: layouts) }
let(:config) { {} }
before do
allow(compilation_context).to receive(:site) { site }
end
subject { executor.find_layout(arg) }
context 'layout with cleaned identifier exists' do
let(:arg) { '/default' }
let(:layouts) do
[Nanoc::Int::Layout.new('head <%= @foo %> foot', {}, Nanoc::Identifier.new('/default/', type: :legacy))]
end
it { is_expected.to eq(layouts[0]) }
end
context 'no layout with cleaned identifier exists' do
let(:layouts) do
[Nanoc::Int::Layout.new('head <%= @foo %> foot', {}, '/default.erb')]
end
context 'globs' do
let(:config) { { string_pattern_type: 'glob' } }
let(:arg) { '/default.*' }
it { is_expected.to eq(layouts[0]) }
end
context 'no globs' do
let(:config) { { string_pattern_type: 'legacy' } }
let(:arg) { '/default.*' }
it 'raises' do
expect { subject }.to raise_error(Nanoc::Int::Errors::UnknownLayout)
end
end
end
end
end
nanoc-4.11.0/nanoc/spec/nanoc/base/services/instrumentor_spec.rb000066400000000000000000000007461340050175000246700ustar00rootroot00000000000000# frozen_string_literal: true
describe(Nanoc::Int::Instrumentor) do
subject { described_class }
before { Timecop.freeze(Time.local(2008, 9, 1, 10, 5, 0)) }
after { Timecop.return }
it 'sends notification' do
expect do
subject.call(:sample_notification, 'garbage', 123) do
# Go to a few seconds in the future
Timecop.freeze(Time.local(2008, 9, 1, 10, 5, 5))
end
end.to send_notification(:sample_notification, 5.0, 'garbage', 123)
end
end
nanoc-4.11.0/nanoc/spec/nanoc/base/services/item_rep_router_spec.rb000066400000000000000000000145531340050175000253240ustar00rootroot00000000000000# frozen_string_literal: true
describe(Nanoc::Int::ItemRepRouter) do
subject(:item_rep_router) { described_class.new(reps, action_provider, site) }
let(:reps) { double(:reps) }
let(:action_provider) { double(:action_provider) }
let(:site) { double(:site, config: config) }
let(:config) { Nanoc::Int::Configuration.new(dir: Dir.getwd).with_defaults }
describe '#run' do
subject { item_rep_router.run }
let(:item) { Nanoc::Int::Item.new('content', {}, '/foo.md') }
let(:reps) do
[
Nanoc::Int::ItemRep.new(item, :default),
Nanoc::Int::ItemRep.new(item, :csv),
]
end
let(:memory_without_paths) do
actions =
[
Nanoc::Int::ProcessingActions::Filter.new(:erb, {}),
Nanoc::Int::ProcessingActions::Snapshot.new([], []),
]
Nanoc::Int::ActionSequence.new(nil, actions: actions)
end
let(:action_sequence_for_default) do
actions =
[
Nanoc::Int::ProcessingActions::Filter.new(:erb, {}),
Nanoc::Int::ProcessingActions::Snapshot.new([:last], ['/foo/index.html']),
]
Nanoc::Int::ActionSequence.new(nil, actions: actions)
end
let(:action_sequence_for_csv) do
actions =
[
Nanoc::Int::ProcessingActions::Filter.new(:erb, {}),
Nanoc::Int::ProcessingActions::Snapshot.new([:last], ['/foo.csv']),
]
Nanoc::Int::ActionSequence.new(nil, actions: actions)
end
example do
allow(action_provider).to receive(:action_sequence_for).with(reps[0]).and_return(action_sequence_for_default)
allow(action_provider).to receive(:action_sequence_for).with(reps[1]).and_return(action_sequence_for_csv)
subject
expect(reps[0].raw_paths).to eql(last: [Dir.getwd + '/output/foo/index.html'])
expect(reps[0].paths).to eql(last: ['/foo/'])
expect(reps[1].raw_paths).to eql(last: [Dir.getwd + '/output/foo.csv'])
expect(reps[1].paths).to eql(last: ['/foo.csv'])
end
it 'picks the paths last returned' do
allow(action_provider).to receive(:action_sequence_for)
.with(reps[0]).and_return(memory_without_paths, action_sequence_for_default)
allow(action_provider).to receive(:action_sequence_for)
.with(reps[1]).and_return(memory_without_paths, action_sequence_for_csv)
subject
expect(reps[0].raw_paths).to eql(last: [Dir.getwd + '/output/foo/index.html'])
expect(reps[0].paths).to eql(last: ['/foo/'])
expect(reps[1].raw_paths).to eql(last: [Dir.getwd + '/output/foo.csv'])
expect(reps[1].paths).to eql(last: ['/foo.csv'])
end
end
describe '#route_rep' do
subject { item_rep_router.route_rep(rep, paths, snapshot_names, paths_to_reps) }
let(:snapshot_names) { [:foo] }
let(:rep) { Nanoc::Int::ItemRep.new(item, :default) }
let(:item) { Nanoc::Int::Item.new('content', {}, '/foo.md') }
let(:paths_to_reps) { {} }
context 'basic path is nil' do
let(:paths) { [] }
it 'assigns no paths' do
subject
expect(rep.raw_paths[:foo]).to be_empty
end
end
context 'basic path is not nil' do
let(:paths) { ['/foo/index.html'] }
context 'other snapshot with this path already exists' do
let(:paths_to_reps) { { '/foo/index.html' => Nanoc::Int::ItemRep.new(item, :other) } }
it 'errors' do
expect { subject }.to raise_error(Nanoc::Int::ItemRepRouter::IdenticalRoutesError, 'The item representations /foo.md (rep name :default) and /foo.md (rep name :other) are both routed to /foo/index.html.')
end
end
context 'path is unique' do
context 'single path' do
it 'sets the raw path' do
subject
expect(rep.raw_paths).to eql(foo: [Dir.getwd + '/output/foo/index.html'])
end
it 'sets the path' do
subject
expect(rep.paths).to eql(foo: ['/foo/'])
end
it 'adds to paths_to_reps' do
subject
expect(paths_to_reps).to have_key('/foo/index.html')
end
context 'path does not start with a slash' do
let(:paths) { ['foo/index.html'] }
it 'errors' do
expect { subject }.to raise_error(Nanoc::Int::ItemRepRouter::RouteWithoutSlashError, 'The item representation /foo.md (rep name :default) is routed to foo/index.html, which does not start with a slash, as required.')
end
end
context 'path is not UTF-8' do
let(:paths) { ['/foo/index.html'.encode('ISO-8859-1')] }
it 'sets the path as UTF-8' do
subject
expect(rep.paths).to eql(foo: ['/foo/'])
expect(rep.paths[:foo].first.encoding.to_s).to eql('UTF-8')
end
it 'sets the raw path as UTF-8' do
subject
expect(rep.raw_paths).to eql(foo: [Dir.getwd + '/output/foo/index.html'])
expect(rep.raw_paths[:foo].first.encoding.to_s).to eql('UTF-8')
end
end
end
context 'multiple paths' do
let(:paths) { ['/foo/index.html', '/bar/index.html'] }
it 'sets the raw paths' do
subject
expect(rep.raw_paths).to eql(foo: [Dir.getwd + '/output/foo/index.html', Dir.getwd + '/output/bar/index.html'])
end
it 'sets the paths' do
subject
expect(rep.paths).to eql(foo: ['/foo/', '/bar/'])
end
it 'adds to paths_to_reps' do
subject
expect(paths_to_reps).to have_key('/foo/index.html')
expect(paths_to_reps).to have_key('/bar/index.html')
end
end
end
end
end
describe '#strip_index_filename' do
subject { item_rep_router.strip_index_filename(basic_path) }
context 'basic path ends with /index.html' do
let(:basic_path) { '/bar/index.html' }
it { is_expected.to eql('/bar/') }
end
context 'basic path contains /index.html' do
let(:basic_path) { '/bar/index.html/foo' }
it { is_expected.to eql('/bar/index.html/foo') }
end
context 'basic path ends with xindex.html' do
let(:basic_path) { '/bar/xindex.html' }
it { is_expected.to eql('/bar/xindex.html') }
end
context 'basic path does not contain /index.html' do
let(:basic_path) { '/bar/foo.html' }
it { is_expected.to eql('/bar/foo.html') }
end
end
end
nanoc-4.11.0/nanoc/spec/nanoc/base/services/item_rep_selector_spec.rb000066400000000000000000000126541340050175000256240ustar00rootroot00000000000000# frozen_string_literal: true
describe Nanoc::Int::ItemRepSelector do
let(:selector) { described_class.new(reps_for_selector) }
let(:item) do
Nanoc::Int::Item.new('stuff', {}, '/foo.md')
end
let(:reps_array) do
[
Nanoc::Int::ItemRep.new(item, :a),
Nanoc::Int::ItemRep.new(item, :b),
Nanoc::Int::ItemRep.new(item, :c),
Nanoc::Int::ItemRep.new(item, :d),
Nanoc::Int::ItemRep.new(item, :e),
]
end
let(:reps_for_selector) { reps_array }
let(:names_to_reps) do
reps_array.each_with_object({}) do |rep, acc|
acc[rep.name] = rep
end
end
let(:dependencies) { {} }
let(:result) do
tentatively_yielded = []
successfully_yielded = []
selector.each do |rep|
tentatively_yielded << rep.name
dependencies.fetch(rep.name, []).each do |name|
unless successfully_yielded.include?(name)
raise Nanoc::Int::Errors::UnmetDependency.new(names_to_reps[name])
end
end
successfully_yielded << rep.name
end
[tentatively_yielded, successfully_yielded]
end
let(:tentatively_yielded) { result[0] }
let(:successfully_yielded) { result[1] }
describe 'error' do
context 'plain error' do
subject { selector.each { |_rep| raise 'heh' } }
it 'raises' do
expect { subject }.to raise_error(RuntimeError, 'heh')
end
end
context 'plain dependency error' do
subject do
idx = 0
selector.each do |_rep|
idx += 1
raise Nanoc::Int::Errors::UnmetDependency.new(reps_array[2]) if idx == 1
end
end
it 'does not raise' do
expect { subject }.not_to raise_error
end
end
context 'wrapped error' do
subject do
selector.each do |rep|
begin
raise 'heh'
rescue => e
raise Nanoc::Int::Errors::CompilationError.new(e, rep)
end
end
end
it 'raises original error' do
expect { subject }.to raise_error(Nanoc::Int::Errors::CompilationError) do |err|
expect(err.unwrap).to be_a(RuntimeError)
expect(err.unwrap.message).to eq('heh')
end
end
end
context 'wrapped dependency error' do
subject do
idx = 0
selector.each do |rep|
idx += 1
begin
raise Nanoc::Int::Errors::UnmetDependency.new(reps_array[2]) if idx == 1
rescue => e
raise Nanoc::Int::Errors::CompilationError.new(e, rep)
end
end
end
it 'does not raise' do
expect { subject }.not_to raise_error
end
end
end
describe 'cycle' do
context 'dependency on self' do
subject do
selector.each { |r| raise Nanoc::Int::Errors::UnmetDependency.new(r) }
end
example do
expect { subject }.to raise_error(Nanoc::Int::Errors::DependencyCycle, <<~EOS)
The site cannot be compiled because there is a dependency cycle:
(1) item /foo.md, rep :a, uses compiled content of (1)
EOS
end
end
context 'cycle with three dependencies' do
subject do
selector.each do |r|
case r
when reps_array[0]
raise Nanoc::Int::Errors::UnmetDependency.new(reps_array[1])
when reps_array[1]
raise Nanoc::Int::Errors::UnmetDependency.new(reps_array[2])
when reps_array[2]
raise Nanoc::Int::Errors::UnmetDependency.new(reps_array[0])
end
end
end
example do
expect { subject }.to raise_error(Nanoc::Int::Errors::DependencyCycle, <<~EOS)
The site cannot be compiled because there is a dependency cycle:
(1) item /foo.md, rep :a, uses compiled content of
(2) item /foo.md, rep :b, uses compiled content of
(3) item /foo.md, rep :c, uses compiled content of (1)
EOS
end
end
end
describe 'yield order' do
context 'linear dependencies' do
let(:dependencies) do
{
a: [:b],
b: [:c],
c: [:d],
d: [:e],
e: [],
}
end
example do
expect(successfully_yielded).to eq %i[e d c b a]
expect(tentatively_yielded).to eq %i[a b c d e d c b a]
end
end
context 'no dependencies' do
let(:dependencies) do
{}
end
example do
expect(successfully_yielded).to eq %i[a b c d e]
expect(tentatively_yielded).to eq %i[a b c d e]
end
end
context 'star dependencies' do
let(:dependencies) do
{
a: %i[b c d e],
}
end
example do
expect(successfully_yielded).to eq %i[b c d e a]
expect(tentatively_yielded).to eq %i[a b a c a d a e a]
end
end
context 'star dependencies; selectively recompiling' do
let(:reps_for_selector) { reps_array.first(1) }
let(:dependencies) do
{
a: %i[b c d e],
}
end
example do
expect(successfully_yielded).to eq %i[b c d e a]
expect(tentatively_yielded).to eq %i[a b a c a d a e a]
end
end
context 'unrelated roots' do
let(:dependencies) do
{
a: [:d],
b: [:e],
c: [],
}
end
it 'picks prioritised roots' do
expect(successfully_yielded).to eq %i[d a e b c]
expect(tentatively_yielded).to eq %i[a d a b e b c]
end
end
end
end
nanoc-4.11.0/nanoc/spec/nanoc/base/services/notification_center_spec.rb000066400000000000000000000012661340050175000261430ustar00rootroot00000000000000# frozen_string_literal: true
describe Nanoc::Int::NotificationCenter do
it 'receives notification after subscribing' do
ping_received = false
Nanoc::Int::NotificationCenter.on :ping_received, :test do
ping_received = true
end
Nanoc::Int::NotificationCenter.post :ping_received
expect(ping_received).to be
end
it 'does not receive notification after unsubscribing' do
ping_received = false
Nanoc::Int::NotificationCenter.on :ping_received, :test do
ping_received = true
end
Nanoc::Int::NotificationCenter.remove :ping_received, :test
Nanoc::Int::NotificationCenter.post :ping_received
expect(ping_received).not_to be
end
end
nanoc-4.11.0/nanoc/spec/nanoc/base/services/outdatedness_checker_spec.rb000066400000000000000000000570241340050175000263060ustar00rootroot00000000000000# frozen_string_literal: true
describe Nanoc::Int::OutdatednessChecker do
let(:outdatedness_checker) do
described_class.new(
site: site,
checksum_store: checksum_store,
checksums: checksums,
dependency_store: dependency_store,
action_sequence_store: action_sequence_store,
action_sequences: action_sequences,
reps: reps,
)
end
let(:checksum_store) { double(:checksum_store) }
let(:checksums) do
Nanoc::Int::Compiler::Stages::CalculateChecksums.new(
items: items,
layouts: layouts,
code_snippets: code_snippets,
config: config,
).run
end
let(:dependency_store) do
Nanoc::Int::DependencyStore.new(items, layouts, config)
end
let(:items) { Nanoc::Int::ItemCollection.new(config, [item]) }
let(:layouts) { Nanoc::Int::LayoutCollection.new(config) }
let(:code_snippets) { [] }
let(:site) do
Nanoc::Int::Site.new(
config: config,
code_snippets: code_snippets,
data_source: Nanoc::Int::InMemDataSource.new([], []),
)
end
let(:action_sequence_store) do
Nanoc::Int::ActionSequenceStore.new(config: config)
end
let(:old_action_sequence_for_item_rep) do
Nanoc::Int::ActionSequence.build(item_rep) do |b|
b.add_filter(:erb, {})
end
end
let(:new_action_sequence_for_item_rep) { old_action_sequence_for_item_rep }
let(:action_sequences) do
{ item_rep => new_action_sequence_for_item_rep }
end
let(:reps) do
Nanoc::Int::ItemRepRepo.new
end
let(:item_rep) { Nanoc::Int::ItemRep.new(item, :default) }
let(:item) { Nanoc::Int::Item.new('stuff', {}, '/foo.md') }
before do
reps << item_rep
action_sequence_store[item_rep] = old_action_sequence_for_item_rep.serialize
end
describe 'basic outdatedness reasons' do
subject { outdatedness_checker.send(:basic).outdatedness_status_for(obj).reasons.first }
let(:checksum_store) { Nanoc::Int::ChecksumStore.new(config: config, objects: items.to_a + layouts.to_a) }
let(:config) { Nanoc::Int::Configuration.new(dir: Dir.getwd).with_defaults }
before do
checksum_store.add(item)
allow(site).to receive(:code_snippets).and_return([])
allow(site).to receive(:config).and_return(config)
end
context 'with item' do
let(:obj) { item }
context 'action sequence differs' do
let(:new_action_sequence_for_item_rep) do
Nanoc::Int::ActionSequence.build(item_rep) do |b|
b.add_filter(:super_erb, {})
end
end
it 'is outdated due to rule differences' do
expect(subject).to eql(Nanoc::Int::OutdatednessReasons::RulesModified)
end
end
# …
end
context 'with item rep' do
let(:obj) { item_rep }
context 'action sequence differs' do
let(:new_action_sequence_for_item_rep) do
Nanoc::Int::ActionSequence.build(item_rep) do |b|
b.add_filter(:super_erb, {})
end
end
it 'is outdated due to rule differences' do
expect(subject).to eql(Nanoc::Int::OutdatednessReasons::RulesModified)
end
end
# …
end
context 'with layout' do
# …
end
context 'with item collection' do
let(:obj) { items }
context 'no new items' do
it { is_expected.to be_nil }
end
context 'new items' do
before do
dependency_store.store
new_item = Nanoc::Int::Item.new('stuff', {}, '/newblahz.md')
dependency_store.items = Nanoc::Int::ItemCollection.new(config, [item, new_item])
dependency_store.load
end
it { is_expected.to be_a(Nanoc::Int::OutdatednessReasons::ItemCollectionExtended) }
it 'includes proper raw_content props' do
expect(subject.objects.map(&:identifier).map(&:to_s)).to eq(['/newblahz.md'])
end
end
end
context 'with layout collection' do
let(:obj) { layouts }
context 'no new layouts' do
it { is_expected.to be_nil }
end
context 'new layouts' do
before do
dependency_store.store
new_layout = Nanoc::Int::Layout.new('stuff', {}, '/newblahz.md')
dependency_store.layouts = Nanoc::Int::LayoutCollection.new(config, layouts.to_a + [new_layout])
dependency_store.load
end
it { is_expected.to be_a(Nanoc::Int::OutdatednessReasons::LayoutCollectionExtended) }
it 'includes proper raw_content props' do
expect(subject.objects.map(&:identifier).map(&:to_s)).to eq(['/newblahz.md'])
end
end
end
end
describe '#outdated_due_to_dependencies?' do
subject { outdatedness_checker.send(:outdated_due_to_dependencies?, item) }
let(:checksum_store) { Nanoc::Int::ChecksumStore.new(config: config, objects: items.to_a + layouts.to_a) }
let(:other_item) { Nanoc::Int::Item.new('other stuff', {}, '/other.md') }
let(:other_item_rep) { Nanoc::Int::ItemRep.new(other_item, :default) }
let(:config) { Nanoc::Int::Configuration.new(dir: Dir.getwd).with_defaults }
let(:items) { Nanoc::Int::ItemCollection.new(config, [item, other_item]) }
let(:old_action_sequence_for_other_item_rep) do
Nanoc::Int::ActionSequence.build(other_item_rep) do |b|
b.add_filter(:erb, {})
end
end
let(:new_action_sequence_for_other_item_rep) { old_action_sequence_for_other_item_rep }
let(:action_sequences) do
{
item_rep => new_action_sequence_for_item_rep,
other_item_rep => new_action_sequence_for_other_item_rep,
}
end
before do
reps << other_item_rep
action_sequence_store[other_item_rep] = old_action_sequence_for_other_item_rep.serialize
checksum_store.add(item)
checksum_store.add(other_item)
checksum_store.add(config)
allow(site).to receive(:code_snippets).and_return([])
allow(site).to receive(:config).and_return(config)
end
context 'transitive dependency' do
let(:distant_item) { Nanoc::Int::Item.new('distant stuff', {}, '/distant.md') }
let(:distant_item_rep) { Nanoc::Int::ItemRep.new(distant_item, :default) }
let(:items) do
Nanoc::Int::ItemCollection.new(config, [item, other_item, distant_item])
end
let(:action_sequences) do
{
item_rep => new_action_sequence_for_item_rep,
other_item_rep => new_action_sequence_for_other_item_rep,
distant_item_rep => new_action_sequence_for_other_item_rep,
}
end
before do
reps << distant_item_rep
checksum_store.add(distant_item)
action_sequence_store[distant_item_rep] = old_action_sequence_for_other_item_rep.serialize
end
context 'on attribute + attribute' do
before do
dependency_store.record_dependency(item, other_item, attributes: true)
dependency_store.record_dependency(other_item, distant_item, attributes: true)
end
context 'distant attribute changed' do
before { distant_item.attributes[:title] = 'omg new title' }
it 'has correct outdatedness of item' do
expect(outdatedness_checker.send(:outdated_due_to_dependencies?, item)).not_to be
end
it 'has correct outdatedness of other item' do
expect(outdatedness_checker.send(:outdated_due_to_dependencies?, other_item)).to be
end
end
context 'distant raw content changed' do
before { distant_item.content = Nanoc::Int::TextualContent.new('omg new content') }
it 'has correct outdatedness of item' do
expect(outdatedness_checker.send(:outdated_due_to_dependencies?, item)).not_to be
end
it 'has correct outdatedness of other item' do
expect(outdatedness_checker.send(:outdated_due_to_dependencies?, other_item)).not_to be
end
end
end
context 'on compiled content + attribute' do
before do
dependency_store.record_dependency(item, other_item, compiled_content: true)
dependency_store.record_dependency(other_item, distant_item, attributes: true)
end
context 'distant attribute changed' do
before { distant_item.attributes[:title] = 'omg new title' }
it 'has correct outdatedness of item' do
expect(outdatedness_checker.send(:outdated_due_to_dependencies?, item)).to be
end
it 'has correct outdatedness of other item' do
expect(outdatedness_checker.send(:outdated_due_to_dependencies?, other_item)).to be
end
end
context 'distant raw content changed' do
before { distant_item.content = Nanoc::Int::TextualContent.new('omg new content') }
it 'has correct outdatedness of item' do
expect(outdatedness_checker.send(:outdated_due_to_dependencies?, item)).not_to be
end
it 'has correct outdatedness of other item' do
expect(outdatedness_checker.send(:outdated_due_to_dependencies?, other_item)).not_to be
end
end
end
end
context 'only generic attribute dependency' do
before do
dependency_store.record_dependency(item, other_item, attributes: true)
end
context 'attribute changed' do
before { other_item.attributes[:title] = 'omg new title' }
it { is_expected.to be }
end
context 'raw content changed' do
before { other_item.content = Nanoc::Int::TextualContent.new('omg new content') }
it { is_expected.not_to be }
end
context 'attribute + raw content changed' do
before { other_item.attributes[:title] = 'omg new title' }
before { other_item.content = Nanoc::Int::TextualContent.new('omg new content') }
it { is_expected.to be }
end
context 'path changed' do
let(:new_action_sequence_for_other_item_rep) do
Nanoc::Int::ActionSequence.build(other_item_rep) do |b|
b.add_filter(:erb, {})
b.add_snapshot(:donkey, '/giraffe.txt')
end
end
it { is_expected.not_to be }
end
end
context 'only specific attribute dependency' do
before do
dependency_store.record_dependency(item, other_item, attributes: [:title])
end
context 'attribute changed' do
before { other_item.attributes[:title] = 'omg new title' }
it { is_expected.to be }
end
context 'other attribute changed' do
before { other_item.attributes[:subtitle] = 'tagline here' }
it { is_expected.not_to be }
end
context 'raw content changed' do
before { other_item.content = Nanoc::Int::TextualContent.new('omg new content') }
it { is_expected.not_to be }
end
context 'attribute + raw content changed' do
before { other_item.attributes[:title] = 'omg new title' }
before { other_item.content = Nanoc::Int::TextualContent.new('omg new content') }
it { is_expected.to be }
end
context 'other attribute + raw content changed' do
before { other_item.attributes[:subtitle] = 'tagline here' }
before { other_item.content = Nanoc::Int::TextualContent.new('omg new content') }
it { is_expected.not_to be }
end
context 'path changed' do
let(:new_action_sequence_for_other_item_rep) do
Nanoc::Int::ActionSequence.build(other_item_rep) do |b|
b.add_filter(:erb, {})
b.add_snapshot(:donkey, '/giraffe.txt')
end
end
it { is_expected.not_to be }
end
end
context 'generic dependency on config' do
before do
dependency_store.record_dependency(item, config, attributes: true)
end
context 'nothing changed' do
it { is_expected.not_to be }
end
context 'attribute changed' do
before { config[:title] = 'omg new title' }
it { is_expected.to be }
end
context 'other attribute changed' do
before { config[:subtitle] = 'tagline here' }
it { is_expected.to be }
end
end
context 'specific dependency on config' do
before do
dependency_store.record_dependency(item, config, attributes: [:title])
end
context 'nothing changed' do
it { is_expected.not_to be }
end
context 'attribute changed' do
before { config[:title] = 'omg new title' }
it { is_expected.to be }
end
context 'other attribute changed' do
before { config[:subtitle] = 'tagline here' }
it { is_expected.not_to be }
end
end
context 'only raw content dependency' do
before do
dependency_store.record_dependency(item, other_item, raw_content: true)
end
context 'attribute changed' do
before { other_item.attributes[:title] = 'omg new title' }
it { is_expected.not_to be }
end
context 'raw content changed' do
before { other_item.content = Nanoc::Int::TextualContent.new('omg new content') }
it { is_expected.to be }
end
context 'attribute + raw content changed' do
before { other_item.attributes[:title] = 'omg new title' }
before { other_item.content = Nanoc::Int::TextualContent.new('omg new content') }
it { is_expected.to be }
end
context 'path changed' do
let(:new_action_sequence_for_other_item_rep) do
Nanoc::Int::ActionSequence.build(other_item_rep) do |b|
b.add_filter(:erb, {})
b.add_snapshot(:donkey, '/giraffe.txt')
end
end
it { is_expected.not_to be }
end
end
context 'only path dependency' do
before do
dependency_store.record_dependency(item, other_item, raw_content: true)
end
context 'attribute changed' do
before { other_item.attributes[:title] = 'omg new title' }
it { is_expected.not_to be }
end
context 'raw content changed' do
before { other_item.content = Nanoc::Int::TextualContent.new('omg new content') }
it { is_expected.to be }
end
context 'path changed' do
let(:new_action_sequence_for_other_item_rep) do
Nanoc::Int::ActionSequence.build(other_item_rep) do |b|
b.add_filter(:erb, {})
b.add_snapshot(:donkey, '/giraffe.txt')
end
end
it { is_expected.not_to be }
end
end
context 'attribute + raw content dependency' do
before do
dependency_store.record_dependency(item, other_item, attributes: true, raw_content: true)
end
context 'attribute changed' do
before { other_item.attributes[:title] = 'omg new title' }
it { is_expected.to be }
end
context 'raw content changed' do
before { other_item.content = Nanoc::Int::TextualContent.new('omg new content') }
it { is_expected.to be }
end
context 'attribute + raw content changed' do
before { other_item.attributes[:title] = 'omg new title' }
before { other_item.content = Nanoc::Int::TextualContent.new('omg new content') }
it { is_expected.to be }
end
context 'rules changed' do
let(:new_action_sequence_for_other_item_rep) do
Nanoc::Int::ActionSequence.build(other_item_rep) do |b|
b.add_filter(:erb, {})
b.add_filter(:donkey, {})
end
end
it { is_expected.not_to be }
end
end
context 'attribute + other dependency' do
before do
dependency_store.record_dependency(item, other_item, attributes: true, path: true)
end
context 'attribute changed' do
before { other_item.attributes[:title] = 'omg new title' }
it { is_expected.to be }
end
context 'raw content changed' do
before { other_item.content = Nanoc::Int::TextualContent.new('omg new content') }
it { is_expected.not_to be }
end
end
context 'other dependency' do
before do
dependency_store.record_dependency(item, other_item, path: true)
end
context 'attribute changed' do
before { other_item.attributes[:title] = 'omg new title' }
it { is_expected.not_to be }
end
context 'raw content changed' do
before { other_item.content = Nanoc::Int::TextualContent.new('omg new content') }
it { is_expected.not_to be }
end
end
context 'only item collection dependency' do
context 'dependency on any new item' do
before do
dependency_tracker = Nanoc::Int::DependencyTracker.new(dependency_store)
dependency_tracker.enter(item)
dependency_tracker.bounce(items, raw_content: true)
dependency_store.store
end
context 'nothing changed' do
it { is_expected.not_to be }
end
context 'item added' do
before do
new_item = Nanoc::Int::Item.new('stuff', {}, '/newblahz.md')
dependency_store.items = Nanoc::Int::ItemCollection.new(config, items.to_a + [new_item])
dependency_store.load
end
it { is_expected.to be }
end
context 'item removed' do
before do
dependency_store.items = Nanoc::Int::ItemCollection.new(config, [])
dependency_store.load
end
it { is_expected.not_to be }
end
end
context 'dependency on specific new items (string)' do
before do
dependency_tracker = Nanoc::Int::DependencyTracker.new(dependency_store)
dependency_tracker.enter(item)
dependency_tracker.bounce(items, raw_content: ['/new*'])
dependency_store.store
end
context 'nothing changed' do
it { is_expected.not_to be }
end
context 'matching item added' do
before do
new_item = Nanoc::Int::Item.new('stuff', {}, '/newblahz.md')
dependency_store.items = Nanoc::Int::ItemCollection.new(config, items.to_a + [new_item])
dependency_store.load
end
it { is_expected.to be }
end
context 'non-matching item added' do
before do
new_item = Nanoc::Int::Item.new('stuff', {}, '/nublahz.md')
dependency_store.items = Nanoc::Int::ItemCollection.new(config, items.to_a + [new_item])
dependency_store.load
end
it { is_expected.not_to be }
end
context 'item removed' do
before do
dependency_store.items = Nanoc::Int::ItemCollection.new(config, [])
dependency_store.load
end
it { is_expected.not_to be }
end
end
context 'dependency on specific new items (regex)' do
before do
dependency_tracker = Nanoc::Int::DependencyTracker.new(dependency_store)
dependency_tracker.enter(item)
dependency_tracker.bounce(items, raw_content: [%r{^/new.*}])
dependency_store.store
end
context 'nothing changed' do
it { is_expected.not_to be }
end
context 'matching item added' do
before do
new_item = Nanoc::Int::Item.new('stuff', {}, '/newblahz.md')
dependency_store.items = Nanoc::Int::ItemCollection.new(config, items.to_a + [new_item])
dependency_store.load
end
it { is_expected.to be }
end
context 'non-matching item added' do
before do
new_item = Nanoc::Int::Item.new('stuff', {}, '/nublahz.md')
dependency_store.items = Nanoc::Int::ItemCollection.new(config, items.to_a + [new_item])
dependency_store.load
end
it { is_expected.not_to be }
end
context 'item removed' do
before do
dependency_store.items = Nanoc::Int::ItemCollection.new(config, [])
dependency_store.load
end
it { is_expected.not_to be }
end
end
end
context 'only layout collection dependency' do
context 'dependency on any new layout' do
before do
dependency_tracker = Nanoc::Int::DependencyTracker.new(dependency_store)
dependency_tracker.enter(item)
dependency_tracker.bounce(layouts, raw_content: true)
dependency_store.store
end
context 'nothing changed' do
it { is_expected.not_to be }
end
context 'layout added' do
before do
new_layout = Nanoc::Int::Layout.new('stuff', {}, '/newblahz.md')
dependency_store.layouts = Nanoc::Int::LayoutCollection.new(config, layouts.to_a + [new_layout])
dependency_store.load
end
it { is_expected.to be }
end
context 'layout removed' do
before do
dependency_store.layouts = Nanoc::Int::LayoutCollection.new(config, [])
dependency_store.load
end
it { is_expected.not_to be }
end
end
context 'dependency on specific new layouts (string)' do
before do
dependency_tracker = Nanoc::Int::DependencyTracker.new(dependency_store)
dependency_tracker.enter(item)
dependency_tracker.bounce(layouts, raw_content: ['/new*'])
dependency_store.store
end
context 'nothing changed' do
it { is_expected.not_to be }
end
context 'matching layout added' do
before do
new_layout = Nanoc::Int::Layout.new('stuff', {}, '/newblahz.md')
dependency_store.layouts = Nanoc::Int::LayoutCollection.new(config, layouts.to_a + [new_layout])
dependency_store.load
end
it { is_expected.to be }
end
context 'non-matching layout added' do
before do
new_layout = Nanoc::Int::Layout.new('stuff', {}, '/nublahz.md')
dependency_store.layouts = Nanoc::Int::LayoutCollection.new(config, layouts.to_a + [new_layout])
dependency_store.load
end
it { is_expected.not_to be }
end
context 'layout removed' do
before do
dependency_store.layouts = Nanoc::Int::LayoutCollection.new(config, [])
dependency_store.load
end
it { is_expected.not_to be }
end
end
context 'dependency on specific new layouts (regex)' do
before do
dependency_tracker = Nanoc::Int::DependencyTracker.new(dependency_store)
dependency_tracker.enter(item)
dependency_tracker.bounce(layouts, raw_content: [%r{^/new.*}])
dependency_store.store
end
context 'nothing changed' do
it { is_expected.not_to be }
end
context 'matching layout added' do
before do
new_layout = Nanoc::Int::Layout.new('stuff', {}, '/newblahz.md')
dependency_store.layouts = Nanoc::Int::LayoutCollection.new(config, layouts.to_a + [new_layout])
dependency_store.load
end
it { is_expected.to be }
end
context 'non-matching layout added' do
before do
new_layout = Nanoc::Int::Layout.new('stuff', {}, '/nublahz.md')
dependency_store.layouts = Nanoc::Int::LayoutCollection.new(config, layouts.to_a + [new_layout])
dependency_store.load
end
it { is_expected.not_to be }
end
context 'layout removed' do
before do
dependency_store.layouts = Nanoc::Int::LayoutCollection.new(config, [])
dependency_store.load
end
it { is_expected.not_to be }
end
end
end
end
end
nanoc-4.11.0/nanoc/spec/nanoc/base/services/outdatedness_rules_spec.rb000066400000000000000000000440641340050175000260340ustar00rootroot00000000000000# frozen_string_literal: true
describe Nanoc::Int::OutdatednessRules do
describe '#apply' do
subject { rule_class.instance.apply(obj, outdatedness_checker) }
let(:obj) { item_rep }
let(:outdatedness_checker) do
Nanoc::Int::OutdatednessChecker.new(
site: site,
checksum_store: checksum_store,
checksums: checksums,
dependency_store: dependency_store,
action_sequence_store: action_sequence_store,
action_sequences: action_sequences,
reps: reps,
)
end
let(:item_rep) { Nanoc::Int::ItemRep.new(item, :default) }
let(:item) { Nanoc::Int::Item.new('stuff', {}, '/foo.md') }
let(:layout) { Nanoc::Int::Layout.new('layoutz', {}, '/page.erb') }
let(:config) { Nanoc::Int::Configuration.new(dir: Dir.getwd).with_defaults }
let(:code_snippets) { [] }
let(:objects) { [config] + code_snippets + [item] }
let(:site) do
Nanoc::Int::Site.new(
config: config,
code_snippets: code_snippets,
data_source: Nanoc::Int::InMemDataSource.new(items, layouts),
)
end
let(:action_sequences) { {} }
let(:reps) { Nanoc::Int::ItemRepRepo.new }
let(:dependency_store) { Nanoc::Int::DependencyStore.new(items, layouts, config) }
let(:action_sequence_store) { Nanoc::Int::ActionSequenceStore.new(config: config) }
let(:checksum_store) { Nanoc::Int::ChecksumStore.new(config: config, objects: objects) }
let(:checksums) do
Nanoc::Int::Compiler::Stages::CalculateChecksums.new(
items: items,
layouts: layouts,
code_snippets: code_snippets,
config: config,
).run
end
let(:items) { Nanoc::Int::ItemCollection.new(config, [item]) }
let(:layouts) { Nanoc::Int::LayoutCollection.new(config, [layout]) }
before do
allow(site).to receive(:code_snippets).and_return(code_snippets)
allow(site).to receive(:config).and_return(config)
end
describe 'CodeSnippetsModified' do
let(:rule_class) { Nanoc::Int::OutdatednessRules::CodeSnippetsModified }
context 'no snippets' do
let(:code_snippets) { [] }
it { is_expected.not_to be }
end
context 'only non-outdated snippets' do
let(:code_snippet) { Nanoc::Int::CodeSnippet.new('asdf', 'lib/foo.md') }
let(:code_snippets) { [code_snippet] }
before { checksum_store.add(code_snippet) }
it { is_expected.not_to be }
end
context 'only outdated snippets' do
let(:code_snippet) { Nanoc::Int::CodeSnippet.new('asdf', 'lib/foo.md') }
let(:code_snippet_old) { Nanoc::Int::CodeSnippet.new('aaaaaaaa', 'lib/foo.md') }
let(:code_snippets) { [code_snippet] }
before { checksum_store.add(code_snippet_old) }
it { is_expected.to be }
end
end
describe 'NotWritten' do
let(:rule_class) { Nanoc::Int::OutdatednessRules::NotWritten }
context 'no path' do
before { item_rep.paths = {} }
it { is_expected.not_to be }
end
context 'path for last snapshot' do
let(:path) { Dir.getwd + '/foo.txt' }
before { item_rep.raw_paths = { last: [path] } }
context 'not written' do
it { is_expected.to be }
end
context 'written' do
before { File.write(path, 'hello') }
it { is_expected.not_to be }
end
end
context 'path for other snapshot' do
let(:path) { Dir.getwd + '/foo.txt' }
before { item_rep.raw_paths = { donkey: [path] } }
context 'not written' do
it { is_expected.to be }
end
context 'written' do
before { File.write(path, 'hello') }
it { is_expected.not_to be }
end
end
end
describe 'ContentModified' do
let(:rule_class) { Nanoc::Int::OutdatednessRules::ContentModified }
context 'item' do
let(:obj) { item }
before { reps << item_rep }
context 'no checksum available' do
it { is_expected.to be }
end
context 'checksum available and same' do
before { checksum_store.add(item) }
it { is_expected.not_to be }
end
context 'checksum available, but content different' do
let(:old_item) { Nanoc::Int::Item.new('other stuff!!!!', {}, '/foo.md') }
before { checksum_store.add(old_item) }
it { is_expected.to be }
end
context 'checksum available, but attributes different' do
let(:old_item) { Nanoc::Int::Item.new('stuff', { greeting: 'hi' }, '/foo.md') }
before { checksum_store.add(old_item) }
it { is_expected.not_to be }
end
end
context 'item rep' do
let(:obj) { item_rep }
context 'no checksum available' do
it { is_expected.to be }
end
context 'checksum available and same' do
before { checksum_store.add(item) }
it { is_expected.not_to be }
end
context 'checksum available, but content different' do
let(:old_item) { Nanoc::Int::Item.new('other stuff!!!!', {}, '/foo.md') }
before { checksum_store.add(old_item) }
it { is_expected.to be }
end
context 'checksum available, but attributes different' do
let(:old_item) { Nanoc::Int::Item.new('stuff', { greeting: 'hi' }, '/foo.md') }
before { checksum_store.add(old_item) }
it { is_expected.not_to be }
end
end
end
describe 'AttributesModified' do
let(:rule_class) { Nanoc::Int::OutdatednessRules::AttributesModified }
context 'item' do
let(:obj) { item }
before { reps << item_rep }
context 'no checksum available' do
it { is_expected.to be }
end
context 'checksum available and same' do
before { checksum_store.add(item) }
it { is_expected.not_to be }
end
context 'checksum available, but content different' do
let(:old_item) { Nanoc::Int::Item.new('other stuff!!!!', {}, '/foo.md') }
before { checksum_store.add(old_item) }
it { is_expected.not_to be }
end
context 'checksum available, but attributes different' do
let(:old_item) { Nanoc::Int::Item.new('stuff', { greeting: 'hi' }, '/foo.md') }
before { checksum_store.add(old_item) }
it { is_expected.to be }
it 'has the one changed attribute' do
expect(subject.attributes).to contain_exactly(:greeting)
end
end
context 'attribute kept identical' do
let(:item) { Nanoc::Int::Item.new('stuff', { greeting: 'hi' }, '/foo.md') }
let(:old_item) { Nanoc::Int::Item.new('stuff', { greeting: 'hi' }, '/foo.md') }
before { checksum_store.add(old_item) }
it 'has the one changed attribute' do
expect(subject).to be_nil
end
end
context 'attribute changed' do
let(:item) { Nanoc::Int::Item.new('stuff', { greeting: 'hi' }, '/foo.md') }
let(:old_item) { Nanoc::Int::Item.new('stuff', { greeting: 'ho' }, '/foo.md') }
before { checksum_store.add(old_item) }
it 'has the one changed attribute' do
expect(subject.attributes).to contain_exactly(:greeting)
end
end
context 'attribute deleted' do
let(:item) { Nanoc::Int::Item.new('stuff', { greeting: 'hi' }, '/foo.md') }
let(:old_item) { Nanoc::Int::Item.new('stuff', {}, '/foo.md') }
before { checksum_store.add(old_item) }
it 'has the one changed attribute' do
expect(subject.attributes).to contain_exactly(:greeting)
end
end
context 'attribute added' do
let(:item) { Nanoc::Int::Item.new('stuff', {}, '/foo.md') }
let(:old_item) { Nanoc::Int::Item.new('stuff', { greeting: 'hi' }, '/foo.md') }
before { checksum_store.add(old_item) }
it 'has the one changed attribute' do
expect(subject.attributes).to contain_exactly(:greeting)
end
end
end
context 'item rep' do
let(:obj) { item_rep }
context 'no checksum available' do
it { is_expected.to be }
end
context 'checksum available and same' do
before { checksum_store.add(item) }
it { is_expected.not_to be }
end
context 'checksum available, but content different' do
let(:old_item) { Nanoc::Int::Item.new('other stuff!!!!', {}, '/foo.md') }
before { checksum_store.add(old_item) }
it { is_expected.not_to be }
end
context 'checksum available, but attributes different' do
let(:old_item) { Nanoc::Int::Item.new('stuff', { greeting: 'hi' }, '/foo.md') }
before { checksum_store.add(old_item) }
it { is_expected.to be }
it 'has the one changed attribute' do
expect(subject.attributes).to contain_exactly(:greeting)
end
end
end
context 'config' do
# TODO
end
end
describe 'RulesModified' do
let(:rule_class) { Nanoc::Int::OutdatednessRules::RulesModified }
let(:old_mem) do
Nanoc::Int::ActionSequence.build(item_rep) do |b|
b.add_filter(:erb, {})
end
end
let(:action_sequences) { { item_rep => new_mem } }
before do
action_sequence_store[item_rep] = old_mem.serialize
end
context 'memory is the same' do
let(:new_mem) { old_mem }
it { is_expected.not_to be }
end
context 'memory is different' do
let(:new_mem) do
Nanoc::Int::ActionSequence.build(item_rep) do |b|
b.add_filter(:erb, {})
b.add_filter(:donkey, {})
end
end
it { is_expected.to be }
end
context 'memory is the same, but refers to a layout' do
let(:old_mem) do
Nanoc::Int::ActionSequence.build(item_rep) do |b|
b.add_layout('/page.*', {})
end
end
let(:new_mem) { old_mem }
let(:action_sequences) do
{
item_rep => new_mem,
layout => new_layout_mem,
}
end
before do
action_sequence_store[layout] = old_layout_mem.serialize
end
context 'everything is the same' do
let(:new_layout_mem) do
Nanoc::Int::ActionSequence.build(layout) do |b|
b.add_filter(:erb, {})
end
end
let(:old_layout_mem) { new_layout_mem }
it { is_expected.not_to be }
end
context 'referenced layout does not exist' do
let(:new_layout_mem) do
Nanoc::Int::ActionSequence.build(layout) do |b|
b.add_filter(:erb, {})
end
end
let(:old_layout_mem) do
Nanoc::Int::ActionSequence.build(layout) do |b|
b.add_filter(:haml, {})
end
end
let(:old_mem) do
Nanoc::Int::ActionSequence.build(item_rep) do |b|
b.add_layout('/moo.*', {})
end
end
# Something changed about the layout; the item-on-layout dependency
# will ensure this item is marked as outdated.
it { is_expected.not_to be }
end
context 'filter name is different' do
let(:new_layout_mem) do
Nanoc::Int::ActionSequence.build(layout) do |b|
b.add_filter(:erb, {})
end
end
let(:old_layout_mem) do
Nanoc::Int::ActionSequence.build(layout) do |b|
b.add_filter(:haml, {})
end
end
it { is_expected.to be }
end
context 'params are different' do
let(:new_layout_mem) do
Nanoc::Int::ActionSequence.build(layout) do |b|
b.add_filter(:erb, {})
end
end
let(:old_layout_mem) do
Nanoc::Int::ActionSequence.build(layout) do |b|
b.add_filter(:erb, foo: 123)
end
end
it { is_expected.to be }
end
end
end
describe 'ContentModified, AttributesModified' do
subject do
[
Nanoc::Int::OutdatednessRules::ContentModified,
Nanoc::Int::OutdatednessRules::AttributesModified,
].map { |c| !!c.instance.apply(new_obj, outdatedness_checker) } # rubocop:disable Style/DoubleNegation
end
let(:stored_obj) { raise 'override me' }
let(:new_obj) { raise 'override me' }
let(:items) { Nanoc::Int::ItemCollection.new(config, [new_obj]) }
shared_examples 'a document' do
let(:stored_obj) { klass.new('a', {}, '/foo.md') }
let(:new_obj) { stored_obj }
context 'no checksum data' do
context 'not stored' do
it { is_expected.to eql([true, true]) }
end
context 'stored' do
before { checksum_store.add(stored_obj) }
context 'but content changed afterwards' do
let(:new_obj) { klass.new('aaaaaaaa', {}, '/foo.md') }
it { is_expected.to eql([true, false]) }
end
context 'but attributes changed afterwards' do
let(:new_obj) { klass.new('a', { animal: 'donkey' }, '/foo.md') }
it { is_expected.to eql([false, true]) }
end
context 'and unchanged' do
it { is_expected.to eql([false, false]) }
end
end
end
context 'checksum_data' do
let(:stored_obj) { klass.new('a', {}, '/foo.md', checksum_data: 'cs-data') }
let(:new_obj) { stored_obj }
context 'not stored' do
it { is_expected.to eql([true, true]) }
end
context 'stored' do
before { checksum_store.add(stored_obj) }
context 'but checksum data afterwards' do
# NOTE: ignored for attributes!
let(:new_obj) { klass.new('a', {}, '/foo.md', checksum_data: 'cs-data-new') }
it { is_expected.to eql([true, false]) }
end
context 'and unchanged' do
it { is_expected.to eql([false, false]) }
end
end
end
context 'content_checksum_data' do
let(:stored_obj) { klass.new('a', {}, '/foo.md', content_checksum_data: 'cs-data') }
let(:new_obj) { stored_obj }
context 'not stored' do
it { is_expected.to eql([true, true]) }
end
context 'stored' do
before { checksum_store.add(stored_obj) }
context 'but checksum data afterwards' do
let(:new_obj) { klass.new('a', {}, '/foo.md', content_checksum_data: 'cs-data-new') }
it { is_expected.to eql([true, false]) }
end
context 'and unchanged' do
it { is_expected.to eql([false, false]) }
end
end
end
context 'attributes_checksum_data' do
# NOTE: attributes_checksum_data is ignored!
let(:stored_obj) { klass.new('a', {}, '/foo.md', attributes_checksum_data: 'cs-data') }
let(:new_obj) { stored_obj }
context 'not stored' do
it { is_expected.to eql([true, true]) }
end
context 'stored' do
before { checksum_store.add(stored_obj) }
context 'but checksum data afterwards' do
let(:new_obj) { klass.new('a', {}, '/foo.md', attributes_checksum_data: 'cs-data-new') }
it { is_expected.to eql([false, false]) }
end
context 'and unchanged' do
it { is_expected.to eql([false, false]) }
end
end
end
end
context 'item' do
let(:klass) { Nanoc::Int::Item }
it_behaves_like 'a document'
end
context 'layout' do
let(:klass) { Nanoc::Int::Layout }
it_behaves_like 'a document'
end
# …
end
describe 'UsesAlwaysOutdatedFilter' do
let(:rule_class) { Nanoc::Int::OutdatednessRules::UsesAlwaysOutdatedFilter }
let(:action_sequences) { { item_rep => mem } }
context 'unknown filter' do
let(:mem) do
Nanoc::Int::ActionSequence.build(item_rep) do |b|
b.add_snapshot(:donkey, '/foo.md')
b.add_filter(:asdf, {})
end
end
it { is_expected.not_to be }
end
context 'known filter, not always outdated' do
let(:mem) do
Nanoc::Int::ActionSequence.build(item_rep) do |b|
b.add_snapshot(:donkey, '/foo.md')
b.add_filter(:erb, {})
end
end
it { is_expected.not_to be }
end
context 'known filter, always outdated' do
let(:mem) do
Nanoc::Int::ActionSequence.build(item_rep) do |b|
b.add_snapshot(:donkey, '/foo.md')
b.add_filter(:xsl, {})
end
end
it { is_expected.to be }
end
end
describe 'ItemCollectionExtended' do
let(:rule_class) { Nanoc::Int::OutdatednessRules::ItemCollectionExtended }
let(:obj) { items }
context 'no new item added' do
before do
expect(dependency_store).to receive(:new_items).and_return([])
end
it { is_expected.not_to be }
end
context 'new item added' do
before do
expect(dependency_store).to receive(:new_items).and_return([item])
end
it { is_expected.to be }
end
end
describe 'LayoutCollectionExtended' do
let(:rule_class) { Nanoc::Int::OutdatednessRules::LayoutCollectionExtended }
let(:obj) { layouts }
context 'no new layout added' do
before do
expect(dependency_store).to receive(:new_layouts).and_return([])
end
it { is_expected.not_to be }
end
context 'new layout added' do
before do
expect(dependency_store).to receive(:new_layouts).and_return([layout])
end
it { is_expected.to be }
end
end
end
end
nanoc-4.11.0/nanoc/spec/nanoc/base/services/pruner_spec.rb000066400000000000000000000253551340050175000234350ustar00rootroot00000000000000# frozen_string_literal: true
describe Nanoc::Pruner, stdio: true do
subject(:pruner) { described_class.new(config, reps, dry_run: dry_run, exclude: exclude) }
let(:config) { Nanoc::Int::Configuration.new(hash: {}, dir: Dir.getwd).with_defaults }
let(:dry_run) { false }
let(:exclude) { [] }
let(:reps) do
Nanoc::Int::ItemRepRepo.new.tap do |reps|
reps << Nanoc::Int::ItemRep.new(item, :default).tap do |rep|
rep.raw_paths = { last: [Dir.getwd + '/output/asdf.html'] }
end
reps << Nanoc::Int::ItemRep.new(item, :text).tap do |rep|
rep.raw_paths = { last: [Dir.getwd + '/output/asdf.txt'] }
end
end
end
let(:item) { Nanoc::Int::Item.new('asdf', {}, '/a.md') }
it 'is accessible through Nanoc::Extra::Pruner' do
expect(Nanoc::Extra::Pruner).to equal(Nanoc::Pruner)
end
describe '#filename_excluded?' do
subject { pruner.filename_excluded?(filename) }
let(:filename) { Dir.getwd + '/output/foo/bar.html' }
context 'nothing excluded' do
it { is_expected.to be(false) }
end
context 'matching identifier component excluded' do
let(:exclude) { ['foo'] }
it { is_expected.to be(true) }
end
context 'non-matching identifier component excluded' do
let(:exclude) { ['xyz'] }
it { is_expected.to be(false) }
end
context 'output dir excluded' do
let(:exclude) { ['output'] }
it { is_expected.to be(false) }
end
end
describe '#run' do
subject { pruner.run }
describe 'it removes stray files' do
let(:present_files) do
[
'output/foo.html',
'output/foo.txt',
'output/bar.html',
'output/foo/bar.html',
'output/foo/bar.txt',
'output/output/asdf.txt',
]
end
let(:reps) do
Nanoc::Int::ItemRepRepo.new.tap do |reps|
reps << Nanoc::Int::ItemRep.new(item, :a).tap do |rep|
rep.raw_paths = { last: [Dir.getwd + '/output/foo.html'] }
end
reps << Nanoc::Int::ItemRep.new(item, :b).tap do |rep|
rep.raw_paths = { last: [Dir.getwd + '/output/bar.html'] }
end
reps << Nanoc::Int::ItemRep.new(item, :c).tap do |rep|
rep.raw_paths = { last: [Dir.getwd + '/output/foo/bar.html'] }
end
end
end
before do
present_files.each do |fn|
FileUtils.mkdir_p(File.dirname(fn))
File.write(fn, 'asdf')
end
end
context 'nothing excluded' do
it 'removes /foo.txt' do
expect { subject }
.to change { File.file?('output/foo.txt') }
.from(true)
.to(false)
end
it 'removes /foo/bar.txt' do
expect { subject }
.to change { File.file?('output/foo/bar.txt') }
.from(true)
.to(false)
end
it 'removes /output/asdf.txt' do
expect { subject }
.to change { File.file?('output/output/asdf.txt') }
.from(true)
.to(false)
end
end
context 'foo excluded' do
let(:exclude) { ['foo'] }
it 'removes /foo.txt' do
expect { subject }
.to change { File.file?('output/foo.txt') }
.from(true)
.to(false)
end
it 'keeps /foo/bar.txt' do
expect { subject }
.not_to change { File.file?('output/foo/bar.txt') }
.from(true)
end
it 'removes /output/asdf.txt' do
expect { subject }
.to change { File.file?('output/output/asdf.txt') }
.from(true)
.to(false)
end
end
context 'output excluded' do
let(:exclude) { ['output'] }
it 'removes /foo.txt' do
expect { subject }
.to change { File.file?('output/foo.txt') }
.from(true)
.to(false)
end
it 'removes /foo/bar.txt' do
expect { subject }
.to change { File.file?('output/foo/bar.txt') }
.from(true)
.to(false)
end
it 'keeps /output/asdf.txt' do
expect { subject }
.not_to change { File.file?('output/output/asdf.txt') }
.from(true)
end
end
end
describe 'it removes empty directories' do
let(:present_dirs) do
[
'output/.foo',
'output/foo',
'output/foo/bar',
'output/bar',
'output/output',
'output/output/asdf',
]
end
before do
present_dirs.each do |fn|
FileUtils.mkdir_p(fn)
end
end
context 'nothing excluded' do
it 'removes /.foo' do
expect { subject }
.to change { File.directory?('output/.foo') }
.from(true)
.to(false)
end
it 'removes /foo' do
expect { subject }
.to change { File.directory?('output/foo') }
.from(true)
.to(false)
end
it 'removes /foo/bar' do
expect { subject }
.to change { File.directory?('output/foo/bar') }
.from(true)
.to(false)
end
it 'removes /bar' do
expect { subject }
.to change { File.directory?('output/bar') }
.from(true)
.to(false)
end
it 'removes /output' do
expect { subject }
.to change { File.directory?('output/output') }
.from(true)
.to(false)
end
it 'removes /output/asdf' do
expect { subject }
.to change { File.directory?('output/output/asdf') }
.from(true)
.to(false)
end
end
context 'foo excluded' do
let(:exclude) { ['foo'] }
it 'removes /.foo' do
expect { subject }
.to change { File.directory?('output/.foo') }
.from(true)
.to(false)
end
it 'removes /bar' do
expect { subject }
.to change { File.directory?('output/bar') }
.from(true)
.to(false)
end
it 'keeps /foo' do
expect { subject }
.not_to change { File.directory?('output/foo') }
.from(true)
end
it 'keeps /foo/bar' do
expect { subject }
.not_to change { File.directory?('output/foo/bar') }
.from(true)
end
it 'removes /output' do
expect { subject }
.to change { File.directory?('output/output') }
.from(true)
.to(false)
end
it 'removes /output/asdf' do
expect { subject }
.to change { File.directory?('output/output/asdf') }
.from(true)
.to(false)
end
end
context 'output excluded' do
let(:exclude) { ['output'] }
it 'removes /.foo' do
expect { subject }
.to change { File.directory?('output/.foo') }
.from(true)
.to(false)
end
it 'removes /bar' do
expect { subject }
.to change { File.directory?('output/bar') }
.from(true)
.to(false)
end
it 'removes /foo' do
expect { subject }
.to change { File.directory?('output/foo') }
.from(true)
.to(false)
end
it 'removes /foo/bar' do
expect { subject }
.to change { File.directory?('output/foo/bar') }
.from(true)
.to(false)
end
it 'keeps /output' do
expect { subject }
.not_to change { File.directory?('output/output') }
.from(true)
end
it 'keeps /output/asdf' do
expect { subject }
.not_to change { File.directory?('output/output/asdf') }
.from(true)
end
end
end
end
describe '#pathname_components' do
subject { pruner.pathname_components(pathname) }
context 'regular path' do
let(:pathname) { Pathname.new('/a/bb/ccc/dd/e') }
it { is_expected.to eql(%w[/ a bb ccc dd e]) }
end
end
describe '#files_and_dirs_in' do
subject { pruner.files_and_dirs_in('output/') }
before do
FileUtils.mkdir_p('output/projects')
FileUtils.mkdir_p('output/.git')
File.write('output/asdf.html', 'text
')
File.write('output/.htaccess', 'secret stuff here')
File.write('output/projects/nanoc.html', 'Nanoc is v cool!!
')
File.write('output/.git/HEAD', 'some content here')
end
context 'nothing excluded' do
let(:exclude) { [] }
it 'returns all files' do
files = [
'output/asdf.html',
'output/.htaccess',
'output/projects/nanoc.html',
'output/.git/HEAD',
]
expect(subject[0]).to match_array(files)
end
it 'returns all directories' do
dirs = [
'output/projects',
'output/.git',
]
expect(subject[1]).to match_array(dirs)
end
end
context 'directory (.git) excluded' do
let(:exclude) { ['.git'] }
it 'returns all files' do
files = [
'output/asdf.html',
'output/.htaccess',
'output/projects/nanoc.html',
]
expect(subject[0]).to match_array(files)
end
it 'returns all directories' do
dirs = [
'output/projects',
]
expect(subject[1]).to match_array(dirs)
end
end
context 'file (.htaccess) excluded' do
let(:exclude) { ['.htaccess'] }
it 'returns all files' do
files = [
'output/asdf.html',
'output/projects/nanoc.html',
'output/.git/HEAD',
]
expect(subject[0]).to match_array(files)
end
it 'returns all directories' do
dirs = [
'output/projects',
'output/.git',
]
expect(subject[1]).to match_array(dirs)
end
end
context 'output dir is a symlink' do
before do
FileUtils.mv('output', 'output-real')
File.symlink('output-real', 'output')
end
before do
if Nanoc.on_windows?
skip 'Symlinks to output dirs are currently not supported on Windows.'
end
end
it 'returns all files' do
files = [
'output/asdf.html',
'output/.htaccess',
'output/projects/nanoc.html',
'output/.git/HEAD',
]
expect(subject[0]).to match_array(files)
end
it 'returns all directories' do
dirs = [
'output/projects',
'output/.git',
]
expect(subject[1]).to match_array(dirs)
end
end
end
end
nanoc-4.11.0/nanoc/spec/nanoc/base/services/temp_filename_factory_spec.rb000066400000000000000000000041621340050175000264470ustar00rootroot00000000000000# frozen_string_literal: true
describe Nanoc::Int::TempFilenameFactory do
subject(:factory) { described_class.new }
let(:prefix) { 'foo' }
describe '#create' do
it 'creates unique paths' do
path_a = subject.create(prefix)
path_b = subject.create(prefix)
expect(path_a).not_to eq(path_b)
end
it 'returns absolute paths' do
path = subject.create(prefix)
expect(path).to match(/\A(C:)?\//)
end
it 'creates the containing directory' do
expect(Dir[subject.root_dir + '/**/*']).to be_empty
path = subject.create(prefix)
expect(File.directory?(File.dirname(path))).to be(true)
end
it 'reuses the same path after cleanup' do
path_a = subject.create(prefix)
subject.cleanup(prefix)
path_b = subject.create(prefix)
expect(path_a).to eq(path_b)
end
it 'does not create the file' do
path = subject.create(prefix)
expect(File.file?(path)).not_to be(true)
end
end
describe '#cleanup' do
subject { factory.cleanup(prefix) }
let!(:path) { factory.create(prefix) }
before { File.write(path, 'hello') }
def files
Dir[factory.root_dir + '/**/*'].select { |fn| File.file?(fn) }
end
it 'removes generated files' do
expect { subject }.to change { files }.from([path]).to([])
end
context 'files with other prefixes exist' do
before do
factory.create('donkey')
end
it 'does not delete root dir' do
expect(File.directory?(factory.root_dir)).to be(true)
expect { subject }.not_to change { File.directory?(factory.root_dir) }
end
end
context 'no files with other prefixes exist' do
it 'deletes root dir' do
expect { subject }.to change { File.directory?(factory.root_dir) }.from(true).to(false)
end
end
end
describe 'other instance' do
let(:other_instance) do
Nanoc::Int::TempFilenameFactory.new
end
it 'creates unique paths across instances' do
path_a = subject.create(prefix)
path_b = other_instance.create(prefix)
expect(path_a).not_to eq(path_b)
end
end
end
nanoc-4.11.0/nanoc/spec/nanoc/base/views/000077500000000000000000000000001340050175000200635ustar00rootroot00000000000000nanoc-4.11.0/nanoc/spec/nanoc/base/views/basic_item_rep_collection_view_spec.rb000066400000000000000000000003671340050175000276420ustar00rootroot00000000000000# frozen_string_literal: true
require_relative 'support/item_rep_collection_view_examples'
describe Nanoc::BasicItemRepCollectionView do
it_behaves_like 'an item rep collection view'
let(:expected_view_class) { Nanoc::BasicItemRepView }
end
nanoc-4.11.0/nanoc/spec/nanoc/base/views/basic_item_rep_view_spec.rb000066400000000000000000000003321340050175000254170ustar00rootroot00000000000000# frozen_string_literal: true
require_relative 'support/item_rep_view_examples'
describe Nanoc::BasicItemRepView do
let(:expected_item_view_class) { Nanoc::BasicItemView }
it_behaves_like 'an item rep view'
end
nanoc-4.11.0/nanoc/spec/nanoc/base/views/compilation_item_rep_collection_view_spec.rb000066400000000000000000000004031340050175000310660ustar00rootroot00000000000000# frozen_string_literal: true
require_relative 'support/item_rep_collection_view_examples'
describe Nanoc::CompilationItemRepCollectionView do
it_behaves_like 'an item rep collection view'
let(:expected_view_class) { Nanoc::CompilationItemRepView }
end
nanoc-4.11.0/nanoc/spec/nanoc/base/views/compilation_item_rep_view_spec.rb000066400000000000000000000104431340050175000266600ustar00rootroot00000000000000# frozen_string_literal: true
require_relative 'support/item_rep_view_examples'
describe Nanoc::CompilationItemRepView do
let(:expected_item_view_class) { Nanoc::CompilationItemView }
it_behaves_like 'an item rep view'
let(:view_context) do
Nanoc::ViewContextForCompilation.new(
reps: Nanoc::Int::ItemRepRepo.new,
items: Nanoc::Int::ItemCollection.new(config),
dependency_tracker: dependency_tracker,
compilation_context: compilation_context,
snapshot_repo: snapshot_repo,
)
end
let(:compilation_context) { double(:compilation_context) }
let(:snapshot_repo) { Nanoc::Int::SnapshotRepo.new }
let(:dependency_tracker) { Nanoc::Int::DependencyTracker.new(dependency_store) }
let(:dependency_store) { Nanoc::Int::DependencyStore.new(empty_items, empty_layouts, config) }
let(:base_item) { Nanoc::Int::Item.new('base', {}, '/base.md') }
let(:empty_items) { Nanoc::Int::ItemCollection.new(config) }
let(:empty_layouts) { Nanoc::Int::LayoutCollection.new(config) }
let(:config) { Nanoc::Int::Configuration.new(dir: Dir.getwd).with_defaults }
before do
dependency_tracker.enter(base_item)
end
describe '#raw_path' do
subject { Fiber.new { view.raw_path }.resume }
let(:view) { described_class.new(rep, view_context) }
let(:rep) do
Nanoc::Int::ItemRep.new(item, :default).tap do |ir|
ir.raw_paths = {
last: [Dir.getwd + '/output/about/index.html'],
}
end
end
let(:item) do
Nanoc::Int::Item.new('content', {}, '/asdf.md')
end
context 'rep is not compiled' do
it 'creates a dependency' do
expect { subject }.to change { dependency_store.objects_causing_outdatedness_of(base_item) }.from([]).to([item])
end
it 'creates a dependency with the right props' do
subject
dep = dependency_store.dependencies_causing_outdatedness_of(base_item)[0]
expect(dep.props.compiled_content?).to eq(true)
expect(dep.props.raw_content?).to eq(false)
expect(dep.props.attributes?).to eq(false)
expect(dep.props.path?).to eq(false)
end
it { should be_a(Nanoc::Int::Errors::UnmetDependency) }
end
context 'rep is compiled' do
before { rep.compiled = true }
context 'file does not exist' do
it 'raises' do
expect { subject }.to raise_error(Nanoc::Int::Errors::InternalInconsistency)
end
end
context 'file exists' do
before do
FileUtils.mkdir_p('output/about')
File.write('output/about/index.html', 'hi!')
end
it 'creates a dependency' do
expect { subject }.to change { dependency_store.objects_causing_outdatedness_of(base_item) }.from([]).to([item])
end
it 'creates a dependency with the right props' do
subject
dep = dependency_store.dependencies_causing_outdatedness_of(base_item)[0]
expect(dep.props.compiled_content?).to eq(true)
expect(dep.props.raw_content?).to eq(false)
expect(dep.props.attributes?).to eq(false)
expect(dep.props.path?).to eq(false)
end
it { should eq(Dir.getwd + '/output/about/index.html') }
end
end
end
describe '#compiled_content' do
subject { view.compiled_content }
let(:view) { described_class.new(rep, view_context) }
let(:rep) do
Nanoc::Int::ItemRep.new(item, :default).tap do |ir|
ir.compiled = true
ir.snapshot_defs = [
Nanoc::Int::SnapshotDef.new(:last, binary: false),
]
end
end
let(:item) do
Nanoc::Int::Item.new('content', {}, '/asdf.md')
end
before do
snapshot_repo.set(rep, :last, Nanoc::Int::TextualContent.new('Hallo'))
end
it 'creates a dependency' do
expect { subject }
.to change { dependency_store.objects_causing_outdatedness_of(base_item) }
.from([])
.to([item])
end
it 'creates a dependency with the right props' do
subject
dep = dependency_store.dependencies_causing_outdatedness_of(base_item)[0]
expect(dep.props.compiled_content?).to eq(true)
expect(dep.props.raw_content?).to eq(false)
expect(dep.props.attributes?).to eq(false)
expect(dep.props.path?).to eq(false)
end
it { should eq('Hallo') }
end
end
nanoc-4.11.0/nanoc/spec/nanoc/base/views/config_view_spec.rb000066400000000000000000000064461340050175000237330ustar00rootroot00000000000000# frozen_string_literal: true
describe Nanoc::ConfigView do
let(:config) do
Nanoc::Int::Configuration.new(dir: Dir.getwd, hash: hash)
end
let(:hash) { { amount: 9000, animal: 'donkey', foo: { bar: :baz } } }
let(:view) { described_class.new(config, view_context) }
let(:view_context) do
Nanoc::ViewContextForCompilation.new(
reps: Nanoc::Int::ItemRepRepo.new,
items: Nanoc::Int::ItemCollection.new(config),
dependency_tracker: dependency_tracker,
compilation_context: double(:compilation_context),
snapshot_repo: double(:snapshot_repo),
)
end
let(:dependency_tracker) { double(:dependency_tracker) }
describe '#frozen?' do
subject { view.frozen? }
context 'non-frozen config' do
it { is_expected.to be(false) }
end
context 'frozen config' do
before { config.freeze }
it { is_expected.to be(true) }
end
end
describe '#[]' do
subject { view[key] }
before do
expect(dependency_tracker).to receive(:bounce).with(config, attributes: [key])
end
context 'with existing key' do
let(:key) { :animal }
it { is_expected.to eql('donkey') }
end
context 'with non-existing key' do
let(:key) { :weapon }
it { is_expected.to eql(nil) }
end
end
describe '#fetch' do
before do
expect(dependency_tracker).to receive(:bounce).with(config, attributes: [key])
end
context 'with existing key' do
let(:key) { :animal }
subject { view.fetch(key) }
it { is_expected.to eql('donkey') }
end
context 'with non-existing key' do
let(:key) { :weapon }
context 'with fallback' do
subject { view.fetch(key, 'nothing sorry') }
it { is_expected.to eql('nothing sorry') }
end
context 'with block' do
subject { view.fetch(key) { 'nothing sorry' } }
it { is_expected.to eql('nothing sorry') }
end
context 'with no fallback and no block' do
subject { view.fetch(key) }
it 'raises' do
expect { subject }.to raise_error(KeyError)
end
end
end
end
describe '#key?' do
subject { view.key?(key) }
before do
expect(dependency_tracker).to receive(:bounce).with(config, attributes: [key])
end
context 'with existing key' do
let(:key) { :animal }
it { is_expected.to eql(true) }
end
context 'with non-existing key' do
let(:key) { :weapon }
it { is_expected.to eql(false) }
end
end
describe '#each' do
before do
expect(dependency_tracker).to receive(:bounce).with(config, attributes: true)
end
example do
res = []
view.each { |k, v| res << [k, v] }
expect(res).to eql([[:amount, 9000], [:animal, 'donkey'], [:foo, { bar: :baz }]])
end
end
describe '#dig' do
subject { view.dig(*keys) }
before do
expect(dependency_tracker).to receive(:bounce).with(config, attributes: [:foo])
end
context 'with existing keys' do
let(:keys) { %i[foo bar] }
it { is_expected.to eql(:baz) }
end
context 'with non-existing keys' do
let(:keys) { %i[foo baz bar] }
it { is_expected.to be_nil }
end
end
describe '#inspect' do
subject { view.inspect }
it { is_expected.to eql('') }
end
end
nanoc-4.11.0/nanoc/spec/nanoc/base/views/item_collection_with_reps_view_spec.rb000066400000000000000000000012441340050175000277120ustar00rootroot00000000000000# frozen_string_literal: true
require_relative 'support/identifiable_collection_view_examples'
describe Nanoc::ItemCollectionWithRepsView do
let(:view_class) { Nanoc::CompilationItemView }
let(:collection_class) { Nanoc::Int::ItemCollection }
it_behaves_like 'an identifiable collection view'
describe '#inspect' do
let(:wrapped) do
Nanoc::Int::ItemCollection.new(config)
end
let(:view) { described_class.new(wrapped, view_context) }
let(:view_context) { double(:view_context) }
let(:config) { { string_pattern_type: 'glob' } }
subject { view.inspect }
it { is_expected.to eql('') }
end
end
nanoc-4.11.0/nanoc/spec/nanoc/base/views/item_collection_without_reps_view_spec.rb000066400000000000000000000012441340050175000304420ustar00rootroot00000000000000# frozen_string_literal: true
require_relative 'support/identifiable_collection_view_examples'
describe Nanoc::ItemCollectionWithoutRepsView do
let(:view_class) { Nanoc::BasicItemView }
let(:collection_class) { Nanoc::Int::ItemCollection }
it_behaves_like 'an identifiable collection view'
describe '#inspect' do
let(:wrapped) do
Nanoc::Int::ItemCollection.new(config)
end
let(:view) { described_class.new(wrapped, view_context) }
let(:view_context) { double(:view_context) }
let(:config) { { string_pattern_type: 'glob' } }
subject { view.inspect }
it { is_expected.to eql('') }
end
end
nanoc-4.11.0/nanoc/spec/nanoc/base/views/item_view_spec.rb000066400000000000000000000304451340050175000234200ustar00rootroot00000000000000# frozen_string_literal: true
require_relative 'support/document_view_examples'
describe Nanoc::CompilationItemView do
let(:entity_class) { Nanoc::Int::Item }
let(:other_view_class) { Nanoc::LayoutView }
it_behaves_like 'a document view'
let(:view_context) do
Nanoc::ViewContextForCompilation.new(
reps: reps,
items: items,
dependency_tracker: dependency_tracker,
compilation_context: compilation_context,
snapshot_repo: snapshot_repo,
)
end
let(:reps) { Nanoc::Int::ItemRepRepo.new }
let(:items) { Nanoc::Int::ItemCollection.new(config) }
let(:dependency_tracker) { Nanoc::Int::DependencyTracker.new(dependency_store) }
let(:dependency_store) { Nanoc::Int::DependencyStore.new(empty_items, empty_layouts, config) }
let(:compilation_context) { double(:compilation_context) }
let(:snapshot_repo) { Nanoc::Int::SnapshotRepo.new }
let(:base_item) { Nanoc::Int::Item.new('base', {}, '/base.md') }
let(:empty_items) { Nanoc::Int::ItemCollection.new(config) }
let(:empty_layouts) { Nanoc::Int::LayoutCollection.new(config) }
let(:config) { Nanoc::Int::Configuration.new(dir: Dir.getwd).with_defaults }
before do
dependency_tracker.enter(base_item)
end
describe '#parent' do
let(:item) do
Nanoc::Int::Item.new('me', {}, identifier)
end
let(:view) { described_class.new(item, view_context) }
let(:items) do
Nanoc::Int::ItemCollection.new(
{},
[
item,
parent_item,
].compact,
)
end
subject { view.parent }
context 'with parent' do
context 'full identifier' do
let(:identifier) do
Nanoc::Identifier.new('/parent/me.md')
end
let(:parent_item) do
Nanoc::Int::Item.new('parent', {}, '/parent.md')
end
it 'raises' do
expect { subject }.to raise_error(Nanoc::Int::Errors::CannotGetParentOrChildrenOfNonLegacyItem)
end
end
context 'legacy identifier' do
let(:identifier) do
Nanoc::Identifier.new('/parent/me/', type: :legacy)
end
let(:parent_item) do
Nanoc::Int::Item.new('parent', {}, Nanoc::Identifier.new('/parent/', type: :legacy))
end
it 'returns a view for the parent' do
expect(subject.class).to eql(Nanoc::CompilationItemView)
expect(subject._unwrap).to eql(parent_item)
end
it 'returns a view with the right context' do
expect(subject._context).to equal(view_context)
end
context 'frozen parent' do
before { parent_item.freeze }
it { is_expected.to be_frozen }
end
context 'non-frozen parent' do
it { is_expected.not_to be_frozen }
end
context 'with root parent' do
let(:parent_item) { Nanoc::Int::Item.new('parent', {}, parent_identifier) }
let(:identifier) { Nanoc::Identifier.new('/me/', type: :legacy) }
let(:parent_identifier) { Nanoc::Identifier.new('/', type: :legacy) }
it 'returns a view for the parent' do
expect(subject.class).to eql(Nanoc::CompilationItemView)
expect(subject._unwrap).to eql(parent_item)
end
end
end
end
context 'without parent' do
let(:parent_item) do
nil
end
context 'full identifier' do
let(:identifier) do
Nanoc::Identifier.new('/me.md')
end
it 'raises' do
expect { subject }.to raise_error(Nanoc::Int::Errors::CannotGetParentOrChildrenOfNonLegacyItem)
end
end
context 'legacy identifier' do
let(:identifier) do
Nanoc::Identifier.new('/me/', type: :legacy)
end
it { is_expected.to be_nil }
it { is_expected.to be_frozen }
end
end
end
describe '#children' do
let(:item) do
Nanoc::Int::Item.new('me', {}, identifier)
end
let(:view) { described_class.new(item, view_context) }
let(:items) do
Nanoc::Int::ItemCollection.new(
{},
[
item,
*children,
],
)
end
subject { view.children }
context 'full identifier' do
let(:identifier) do
Nanoc::Identifier.new('/me.md')
end
let(:children) do
[Nanoc::Int::Item.new('child', {}, '/me/child.md')]
end
it 'raises' do
expect { subject }.to raise_error(Nanoc::Int::Errors::CannotGetParentOrChildrenOfNonLegacyItem)
end
end
context 'legacy identifier' do
let(:identifier) do
Nanoc::Identifier.new('/me/', type: :legacy)
end
let(:children) do
[Nanoc::Int::Item.new('child', {}, Nanoc::Identifier.new('/me/child/', type: :legacy))]
end
it 'returns views for the children' do
expect(subject.size).to eql(1)
expect(subject[0].class).to eql(Nanoc::CompilationItemView)
expect(subject[0]._unwrap).to eql(children[0])
end
it { is_expected.to be_frozen }
end
end
describe '#reps' do
let(:item) { Nanoc::Int::Item.new('blah', {}, '/foo.md') }
let(:rep_a) { Nanoc::Int::ItemRep.new(item, :a) }
let(:rep_b) { Nanoc::Int::ItemRep.new(item, :b) }
let(:reps) do
Nanoc::Int::ItemRepRepo.new.tap do |reps|
reps << rep_a
reps << rep_b
end
end
let(:view) { described_class.new(item, view_context) }
subject { view.reps }
it 'returns a proper item rep collection' do
expect(subject.size).to eq(2)
expect(subject.class).to eql(Nanoc::CompilationItemRepCollectionView)
end
it 'returns a view with the right context' do
expect(subject._context).to eq(view_context)
end
end
describe '#compiled_content' do
subject { view.compiled_content(params) }
let(:view) { described_class.new(item, view_context) }
let(:item) do
Nanoc::Int::Item.new('content', {}, '/asdf')
end
let(:reps) do
Nanoc::Int::ItemRepRepo.new.tap do |reps|
reps << rep
end
end
let(:rep) do
Nanoc::Int::ItemRep.new(item, :default).tap do |ir|
ir.compiled = true
ir.snapshot_defs = [
Nanoc::Int::SnapshotDef.new(:last, binary: false),
Nanoc::Int::SnapshotDef.new(:pre, binary: false),
Nanoc::Int::SnapshotDef.new(:post, binary: false),
Nanoc::Int::SnapshotDef.new(:specific, binary: false),
]
end
end
before do
snapshot_repo.set(rep, :last, Nanoc::Int::TextualContent.new('Last Hallo'))
snapshot_repo.set(rep, :pre, Nanoc::Int::TextualContent.new('Pre Hallo'))
snapshot_repo.set(rep, :post, Nanoc::Int::TextualContent.new('Post Hallo'))
snapshot_repo.set(rep, :specific, Nanoc::Int::TextualContent.new('Specific Hallo'))
end
context 'requesting implicit default rep' do
let(:params) { {} }
it { is_expected.to eq('Pre Hallo') }
it 'creates a dependency' do
expect { subject }.to change { dependency_store.objects_causing_outdatedness_of(base_item) }.from([]).to([item])
end
context 'requesting explicit snapshot' do
let(:params) { { snapshot: :specific } }
it { is_expected.to eq('Specific Hallo') }
it 'creates a dependency' do
expect { subject }.to change { dependency_store.objects_causing_outdatedness_of(base_item) }.from([]).to([item])
end
end
end
context 'requesting explicit default rep' do
let(:params) { { rep: :default } }
it 'creates a dependency' do
expect { subject }.to change { dependency_store.objects_causing_outdatedness_of(base_item) }.from([]).to([item])
end
it { is_expected.to eq('Pre Hallo') }
context 'requesting explicit snapshot' do
let(:params) { { snapshot: :specific } }
it { is_expected.to eq('Specific Hallo') }
end
end
context 'requesting other rep' do
let(:params) { { rep: :other } }
it 'raises an error' do
expect { subject }.to raise_error(Nanoc::BasicItemRepCollectionView::NoSuchItemRepError)
end
end
end
describe '#path' do
subject { view.path(params) }
let(:view) { described_class.new(item, view_context) }
let(:item) do
Nanoc::Int::Item.new('content', {}, '/asdf.md')
end
let(:reps) do
Nanoc::Int::ItemRepRepo.new.tap do |reps|
reps << rep
end
end
let(:rep) do
Nanoc::Int::ItemRep.new(item, :default).tap do |ir|
ir.paths = {
last: ['/about/'],
specific: ['/about.txt'],
}
end
end
context 'requesting implicit default rep' do
let(:params) { {} }
it 'creates a dependency' do
expect { subject }.to change { dependency_store.objects_causing_outdatedness_of(base_item) }.from([]).to([item])
end
it { is_expected.to eq('/about/') }
context 'requesting explicit snapshot' do
let(:params) { { snapshot: :specific } }
it { is_expected.to eq('/about.txt') }
end
end
context 'requesting explicit default rep' do
let(:params) { { rep: :default } }
it 'creates a dependency' do
expect { subject }.to change { dependency_store.objects_causing_outdatedness_of(base_item) }.from([]).to([item])
end
it { is_expected.to eq('/about/') }
context 'requesting explicit snapshot' do
let(:params) { { snapshot: :specific } }
it { is_expected.to eq('/about.txt') }
end
end
context 'requesting other rep' do
let(:params) { { rep: :other } }
it 'raises an error' do
expect { subject }.to raise_error(Nanoc::BasicItemRepCollectionView::NoSuchItemRepError)
end
end
end
describe '#binary?' do
# TODO: implement
end
describe '#raw_filename' do
subject { view.raw_filename }
let(:item) do
Nanoc::Int::Item.new(content, { animal: 'donkey' }, '/foo')
end
let(:view) { described_class.new(item, view_context) }
context 'textual content with no raw filename' do
let(:content) { Nanoc::Int::TextualContent.new('asdf') }
it { is_expected.to be_nil }
it 'creates a dependency' do
expect { subject }.to change { dependency_store.objects_causing_outdatedness_of(base_item) }.from([]).to([item])
end
it 'creates a dependency with the right props' do
subject
dep = dependency_store.dependencies_causing_outdatedness_of(base_item)[0]
expect(dep.props.raw_content?).to eq(true)
expect(dep.props.attributes?).to eq(false)
expect(dep.props.compiled_content?).to eq(false)
expect(dep.props.path?).to eq(false)
end
end
context 'textual content with raw filename' do
let(:content) { Nanoc::Int::TextualContent.new('asdf', filename: filename) }
let(:filename) { '/tmp/lol.txt' }
it { is_expected.to eql('/tmp/lol.txt') }
it 'creates a dependency' do
expect { subject }.to change { dependency_store.objects_causing_outdatedness_of(base_item) }.from([]).to([item])
end
it 'creates a dependency with the right props' do
subject
dep = dependency_store.dependencies_causing_outdatedness_of(base_item)[0]
expect(dep.props.raw_content?).to eq(true)
expect(dep.props.attributes?).to eq(false)
expect(dep.props.compiled_content?).to eq(false)
expect(dep.props.path?).to eq(false)
end
end
context 'binary content' do
let(:content) { Nanoc::Int::BinaryContent.new(filename) }
let(:filename) { '/tmp/lol.txt' }
it { is_expected.to eql('/tmp/lol.txt') }
it 'creates a dependency' do
expect { subject }.to change { dependency_store.objects_causing_outdatedness_of(base_item) }.from([]).to([item])
end
it 'creates a dependency with the right props' do
subject
dep = dependency_store.dependencies_causing_outdatedness_of(base_item)[0]
expect(dep.props.raw_content?).to eq(true)
expect(dep.props.attributes?).to eq(false)
expect(dep.props.compiled_content?).to eq(false)
expect(dep.props.path?).to eq(false)
end
end
end
describe '#inspect' do
let(:item) { Nanoc::Int::Item.new('content', {}, '/asdf') }
let(:view) { described_class.new(item, nil) }
subject { view.inspect }
it { is_expected.to eql('') }
end
end
nanoc-4.11.0/nanoc/spec/nanoc/base/views/layout_collection_view_spec.rb000066400000000000000000000012231340050175000262020ustar00rootroot00000000000000# frozen_string_literal: true
require_relative 'support/identifiable_collection_view_examples'
describe Nanoc::LayoutCollectionView do
let(:view_class) { Nanoc::LayoutView }
let(:collection_class) { Nanoc::Int::LayoutCollection }
it_behaves_like 'an identifiable collection view'
describe '#inspect' do
let(:wrapped) do
Nanoc::Int::LayoutCollection.new(config)
end
let(:view) { described_class.new(wrapped, view_context) }
let(:view_context) { double(:view_context) }
let(:config) { { string_pattern_type: 'glob' } }
subject { view.inspect }
it { is_expected.to eql('') }
end
end
nanoc-4.11.0/nanoc/spec/nanoc/base/views/layout_view_spec.rb000066400000000000000000000007651340050175000240010ustar00rootroot00000000000000# frozen_string_literal: true
require_relative 'support/document_view_examples'
describe Nanoc::LayoutView do
let(:entity_class) { Nanoc::Int::Layout }
let(:other_view_class) { Nanoc::CompilationItemView }
it_behaves_like 'a document view'
describe '#inspect' do
let(:item) { Nanoc::Int::Layout.new('content', {}, '/asdf') }
let(:view) { described_class.new(item, nil) }
subject { view.inspect }
it { is_expected.to eql('') }
end
end
nanoc-4.11.0/nanoc/spec/nanoc/base/views/mutable_config_view_spec.rb000066400000000000000000000006521340050175000254350ustar00rootroot00000000000000# frozen_string_literal: true
describe Nanoc::MutableConfigView do
let(:config) { {} }
let(:view) { described_class.new(config, nil) }
describe '#[]=' do
it 'sets attributes' do
view[:awesomeness] = 'rather high'
expect(config[:awesomeness]).to eq('rather high')
end
end
describe '#inspect' do
subject { view.inspect }
it { is_expected.to eql('') }
end
end
nanoc-4.11.0/nanoc/spec/nanoc/base/views/mutable_item_collection_view_spec.rb000066400000000000000000000031611340050175000273370ustar00rootroot00000000000000# frozen_string_literal: true
require_relative 'support/identifiable_collection_view_examples'
require_relative 'support/mutable_identifiable_collection_view_examples'
describe Nanoc::MutableItemCollectionView do
let(:view_class) { Nanoc::MutableItemView }
let(:collection_class) { Nanoc::Int::ItemCollection }
it_behaves_like 'an identifiable collection view'
it_behaves_like 'a mutable identifiable collection view'
let(:config) do
{ string_pattern_type: 'glob' }
end
describe '#create' do
let(:item) do
Nanoc::Int::Layout.new('content', {}, '/asdf')
end
let(:wrapped) do
Nanoc::Int::ItemCollection.new(config, [item])
end
let(:view) { described_class.new(wrapped, nil) }
it 'creates an object' do
view.create('new content', { title: 'New Page' }, '/new')
expect(view._unwrap.size).to eq(2)
expect(view._unwrap['/new'].content.string).to eq('new content')
end
it 'does not update wrapped' do
view.create('new content', { title: 'New Page' }, '/new')
expect(wrapped.size).to eq(1)
expect(wrapped['/new']).to be_nil
end
it 'returns self' do
ret = view.create('new content', { title: 'New Page' }, '/new')
expect(ret).to equal(view)
end
end
describe '#inspect' do
let(:wrapped) do
Nanoc::Int::ItemCollection.new(config)
end
let(:view) { described_class.new(wrapped, view_context) }
let(:view_context) { double(:view_context) }
let(:config) { { string_pattern_type: 'glob' } }
subject { view.inspect }
it { is_expected.to eql('') }
end
end
nanoc-4.11.0/nanoc/spec/nanoc/base/views/mutable_item_view_spec.rb000066400000000000000000000013561340050175000251300ustar00rootroot00000000000000# frozen_string_literal: true
require_relative 'support/mutable_document_view_examples'
describe Nanoc::MutableItemView do
let(:entity_class) { Nanoc::Int::Item }
it_behaves_like 'a mutable document view'
let(:item) { entity_class.new('content', {}, '/asdf') }
let(:view) { described_class.new(item, nil) }
it 'does have rep access' do
expect(view).not_to respond_to(:compiled_content)
expect(view).not_to respond_to(:path)
expect(view).not_to respond_to(:reps)
end
describe '#inspect' do
let(:item) { Nanoc::Int::Item.new('content', {}, '/asdf') }
let(:view) { described_class.new(item, nil) }
subject { view.inspect }
it { is_expected.to eql('') }
end
end
nanoc-4.11.0/nanoc/spec/nanoc/base/views/mutable_layout_collection_view_spec.rb000066400000000000000000000032011340050175000277110ustar00rootroot00000000000000# frozen_string_literal: true
require_relative 'support/identifiable_collection_view_examples'
require_relative 'support/mutable_identifiable_collection_view_examples'
describe Nanoc::MutableLayoutCollectionView do
let(:view_class) { Nanoc::MutableLayoutView }
let(:collection_class) { Nanoc::Int::LayoutCollection }
it_behaves_like 'an identifiable collection view'
it_behaves_like 'a mutable identifiable collection view'
let(:config) do
{ string_pattern_type: 'glob' }
end
describe '#create' do
let(:layout) do
Nanoc::Int::Layout.new('content', {}, '/asdf')
end
let(:wrapped) do
Nanoc::Int::LayoutCollection.new(config, [layout])
end
let(:view) { described_class.new(wrapped, nil) }
it 'creates an object' do
view.create('new content', { title: 'New Page' }, '/new')
expect(view._unwrap.size).to eq(2)
expect(view._unwrap['/new'].content.string).to eq('new content')
end
it 'does not update wrapped' do
view.create('new content', { title: 'New Page' }, '/new')
expect(wrapped.size).to eq(1)
expect(wrapped['/new']).to be_nil
end
it 'returns self' do
ret = view.create('new content', { title: 'New Page' }, '/new')
expect(ret).to equal(view)
end
end
describe '#inspect' do
let(:wrapped) do
Nanoc::Int::LayoutCollection.new(config)
end
let(:view) { described_class.new(wrapped, view_context) }
let(:view_context) { double(:view_context) }
let(:config) { { string_pattern_type: 'glob' } }
subject { view.inspect }
it { is_expected.to eql('') }
end
end
nanoc-4.11.0/nanoc/spec/nanoc/base/views/mutable_layout_view_spec.rb000066400000000000000000000007311340050175000255030ustar00rootroot00000000000000# frozen_string_literal: true
require_relative 'support/mutable_document_view_examples'
describe Nanoc::MutableLayoutView do
let(:entity_class) { Nanoc::Int::Layout }
it_behaves_like 'a mutable document view'
describe '#inspect' do
let(:item) { Nanoc::Int::Item.new('content', {}, '/asdf') }
let(:view) { described_class.new(item, nil) }
subject { view.inspect }
it { is_expected.to eql('') }
end
end
nanoc-4.11.0/nanoc/spec/nanoc/base/views/post_compile_item_rep_collection_view_spec.rb000066400000000000000000000004031340050175000312450ustar00rootroot00000000000000# frozen_string_literal: true
require_relative 'support/item_rep_collection_view_examples'
describe Nanoc::PostCompileItemRepCollectionView do
it_behaves_like 'an item rep collection view'
let(:expected_view_class) { Nanoc::PostCompileItemRepView }
end
nanoc-4.11.0/nanoc/spec/nanoc/base/views/post_compile_item_rep_view_spec.rb000066400000000000000000000137741340050175000270510ustar00rootroot00000000000000# frozen_string_literal: true
require_relative 'support/item_rep_view_examples'
describe Nanoc::PostCompileItemRepView do
let(:expected_item_view_class) { Nanoc::PostCompileItemView }
it_behaves_like 'an item rep view'
let(:item_rep) { Nanoc::Int::ItemRep.new(item, :jacques) }
let(:item) { Nanoc::Int::Item.new('asdf', {}, '/foo') }
let(:view) { described_class.new(item_rep, view_context) }
let(:view_context) do
Nanoc::ViewContextForCompilation.new(
reps: Nanoc::Int::ItemRepRepo.new,
items: Nanoc::Int::ItemCollection.new(config),
dependency_tracker: dependency_tracker,
compilation_context: compilation_context,
snapshot_repo: snapshot_repo,
)
end
let(:reps) { double(:reps) }
let(:items) { Nanoc::Int::ItemCollection.new(config) }
let(:config) { Nanoc::Int::Configuration.new(dir: Dir.getwd).with_defaults }
let(:dependency_tracker) { Nanoc::Int::DependencyTracker.new(double(:dependency_store)) }
let(:compilation_context) { double(:compilation_context, compiled_content_cache: compiled_content_cache) }
let(:snapshot_repo) { double(:snapshot_repo) }
let(:snapshot_contents) do
{
last: Nanoc::Int::TextualContent.new('content-last'),
pre: Nanoc::Int::TextualContent.new('content-pre'),
donkey: Nanoc::Int::TextualContent.new('content-donkey'),
}
end
let(:compiled_content_cache) do
Nanoc::Int::CompiledContentCache.new(config: config).tap do |ccc|
ccc[item_rep] = snapshot_contents
end
end
describe '#raw_path' do
context 'no args' do
subject { view.raw_path }
it 'does not raise' do
subject
end
context 'no path specified' do
it { is_expected.to be_nil }
end
context 'path for default snapshot specified' do
before do
item_rep.raw_paths = { last: [Dir.getwd + '/output/about/index.html'] }
end
it { is_expected.to eql(Dir.getwd + '/output/about/index.html') }
end
context 'path specified, but not for default snapshot' do
before do
item_rep.raw_paths = { pre: [Dir.getwd + '/output/about/index.html'] }
end
it { is_expected.to be_nil }
end
end
context 'snapshot arg' do
subject { view.raw_path(snapshot: :special) }
it 'does not raise' do
subject
end
context 'no path specified' do
it { is_expected.to be_nil }
end
context 'path for default snapshot specified' do
before do
item_rep.raw_paths = { special: [Dir.getwd + '/output/about/index.html'] }
end
it { is_expected.to eql(Dir.getwd + '/output/about/index.html') }
end
context 'path specified, but not for default snapshot' do
before do
item_rep.raw_paths = { pre: [Dir.getwd + '/output/about/index.html'] }
end
it { is_expected.to be_nil }
end
end
end
describe '#compiled_content' do
subject { view.compiled_content }
context 'binary' do
let(:snapshot_contents) do
{
last: Nanoc::Int::TextualContent.new('content-last'),
pre: Nanoc::Int::BinaryContent.new('/content/pre'),
donkey: Nanoc::Int::TextualContent.new('content-donkey'),
}
end
it 'raises error' do
expect { subject }.to raise_error(Nanoc::Int::Errors::CannotGetCompiledContentOfBinaryItem, 'You cannot access the compiled content of a binary item representation (but you can access the path). The offending item rep is /foo (rep name :jacques).')
end
end
shared_examples 'returns pre content' do
example { expect(subject).to eq('content-pre') }
end
shared_examples 'returns last content' do
example { expect(subject).to eq('content-last') }
end
shared_examples 'returns donkey content' do
example { expect(subject).to eq('content-donkey') }
end
shared_examples 'raises no-such-snapshot error' do
it 'raises error' do
err = Nanoc::Int::Errors::NoSuchSnapshot
expect { subject }.to raise_error(err)
end
end
context 'textual' do
context 'snapshot provided' do
subject { view.compiled_content(snapshot: :donkey) }
let(:expected_snapshot) { :donkey }
context 'snapshot exists' do
include_examples 'returns donkey content'
end
context 'snapshot does not exist' do
let(:snapshot_contents) do
{
last: Nanoc::Int::TextualContent.new('content-last'),
pre: Nanoc::Int::TextualContent.new('content-pre'),
}
end
include_examples 'raises no-such-snapshot error'
end
end
context 'no snapshot provided' do
context 'pre and last snapshots exist' do
let(:snapshot_contents) do
{
last: Nanoc::Int::TextualContent.new('content-last'),
pre: Nanoc::Int::TextualContent.new('content-pre'),
donkey: Nanoc::Int::TextualContent.new('content-donkey'),
}
end
include_examples 'returns pre content'
end
context 'pre snapshot exists' do
let(:snapshot_contents) do
{
pre: Nanoc::Int::TextualContent.new('content-pre'),
donkey: Nanoc::Int::TextualContent.new('content-donkey'),
}
end
include_examples 'returns pre content'
end
context 'last snapshot exists' do
let(:snapshot_contents) do
{
last: Nanoc::Int::TextualContent.new('content-last'),
donkey: Nanoc::Int::TextualContent.new('content-donkey'),
}
end
include_examples 'returns last content'
end
context 'neither pre nor last snapshot exists' do
let(:snapshot_contents) do
{
donkey: Nanoc::Int::TextualContent.new('content-donkey'),
}
end
include_examples 'raises no-such-snapshot error'
end
end
end
end
end
nanoc-4.11.0/nanoc/spec/nanoc/base/views/post_compile_item_view_spec.rb000066400000000000000000000031651340050175000261740ustar00rootroot00000000000000# frozen_string_literal: true
describe Nanoc::PostCompileItemView do
let(:item) { Nanoc::Int::Item.new('blah', {}, '/foo.md') }
let(:rep_a) { Nanoc::Int::ItemRep.new(item, :no_mod) }
let(:rep_b) { Nanoc::Int::ItemRep.new(item, :modded).tap { |r| r.modified = true } }
let(:reps) do
Nanoc::Int::ItemRepRepo.new.tap do |reps|
reps << rep_a
reps << rep_b
end
end
let(:view_context) { double(:view_context, reps: reps) }
let(:view) { described_class.new(item, view_context) }
shared_examples 'a method that returns modified reps only' do
it 'returns only modified items' do
expect(subject.size).to eq(1)
expect(subject.map(&:name)).to eq(%i[modded])
end
it 'returns an array' do
expect(subject.class).to eql(Array)
end
end
shared_examples 'a method that returns PostCompileItemRepViews' do
it 'returns PostCompileItemRepViews' do
expect(subject).to all(be_a(Nanoc::PostCompileItemRepView))
end
end
describe '#modified_reps' do
subject { view.modified_reps }
it_behaves_like 'a method that returns modified reps only'
it_behaves_like 'a method that returns PostCompileItemRepViews'
end
describe '#modified' do
subject { view.modified }
it_behaves_like 'a method that returns modified reps only'
it_behaves_like 'a method that returns PostCompileItemRepViews'
end
describe '#reps' do
subject { view.reps }
it_behaves_like 'a method that returns PostCompileItemRepViews'
it 'returns a PostCompileItemRepCollectionView' do
expect(subject).to be_a(Nanoc::PostCompileItemRepCollectionView)
end
end
end
nanoc-4.11.0/nanoc/spec/nanoc/base/views/support/000077500000000000000000000000001340050175000215775ustar00rootroot00000000000000nanoc-4.11.0/nanoc/spec/nanoc/base/views/support/document_view_examples.rb000066400000000000000000000231551340050175000267000ustar00rootroot00000000000000# frozen_string_literal: true
shared_examples 'a document view' do
let(:view) { described_class.new(document, view_context) }
let(:view_context) do
Nanoc::ViewContextForCompilation.new(
reps: Nanoc::Int::ItemRepRepo.new,
items: Nanoc::Int::ItemCollection.new(config),
dependency_tracker: dependency_tracker,
compilation_context: double(:compilation_context),
snapshot_repo: double(:snapshot_repo),
)
end
let(:dependency_tracker) { Nanoc::Int::DependencyTracker.new(dependency_store) }
let(:dependency_store) { Nanoc::Int::DependencyStore.new(empty_items, empty_layouts, config) }
let(:base_item) { Nanoc::Int::Item.new('base', {}, '/base.md') }
let(:empty_items) { Nanoc::Int::ItemCollection.new(config) }
let(:empty_layouts) { Nanoc::Int::LayoutCollection.new(config) }
let(:config) { Nanoc::Int::Configuration.new(dir: Dir.getwd).with_defaults }
before do
dependency_tracker.enter(base_item)
end
describe '#frozen?' do
let(:document) { entity_class.new('content', {}, '/asdf') }
subject { view.frozen? }
context 'non-frozen document' do
it { is_expected.to be(false) }
end
context 'frozen document' do
before { document.freeze }
it { is_expected.to be(true) }
end
end
describe '#== and #eql?' do
let(:document) { entity_class.new('content', {}, '/asdf') }
context 'comparing with document with same identifier' do
let(:other) { entity_class.new('content', {}, '/asdf') }
it 'is ==' do
expect(view).to eq(other)
end
it 'is not eql?' do
expect(view).not_to eql(other)
end
end
context 'comparing with document with different identifier' do
let(:other) { entity_class.new('content', {}, '/fdsa') }
it 'is not ==' do
expect(view).not_to eq(other)
end
it 'is not eql?' do
expect(view).not_to eql(other)
end
end
context 'comparing with document view with same identifier' do
let(:other) { other_view_class.new(entity_class.new('content', {}, '/asdf'), nil) }
it 'is ==' do
expect(view).to eq(other)
end
it 'is not eql?' do
expect(view).not_to eql(other)
end
end
context 'comparing with document view with different identifier' do
let(:other) { other_view_class.new(entity_class.new('content', {}, '/fdsa'), nil) }
it 'is not ==' do
expect(view).not_to eq(other)
end
it 'is not eql?' do
expect(view).not_to eql(other)
end
end
context 'comparing with other object' do
let(:other) { nil }
it 'is not ==' do
expect(view).not_to eq(other)
end
it 'is not eql?' do
expect(view).not_to eql(other)
end
end
end
describe '#[]' do
let(:document) { entity_class.new('stuff', { animal: 'donkey' }, '/foo') }
subject { view[key] }
context 'with existant key' do
let(:key) { :animal }
it { is_expected.to eql('donkey') }
it 'creates a dependency' do
expect { subject }.to change { dependency_store.objects_causing_outdatedness_of(base_item) }.from([]).to([document])
end
it 'creates a dependency with the right props' do
subject
dep = dependency_store.dependencies_causing_outdatedness_of(base_item)[0]
expect(dep.props.attributes?).to eq(true)
expect(dep.props.raw_content?).to eq(false)
expect(dep.props.compiled_content?).to eq(false)
expect(dep.props.path?).to eq(false)
end
end
context 'with non-existant key' do
let(:key) { :weapon }
it { is_expected.to eql(nil) }
it 'creates a dependency' do
expect { subject }.to change { dependency_store.objects_causing_outdatedness_of(base_item) }.from([]).to([document])
end
it 'creates a dependency with the right props' do
subject
dep = dependency_store.dependencies_causing_outdatedness_of(base_item)[0]
expect(dep.props.attributes?).to eq(true)
expect(dep.props.raw_content?).to eq(false)
expect(dep.props.compiled_content?).to eq(false)
expect(dep.props.path?).to eq(false)
end
end
end
describe '#attributes' do
let(:document) { entity_class.new('stuff', { animal: 'donkey' }, '/foo') }
subject { view.attributes }
it 'creates a dependency' do
expect { subject }.to change { dependency_store.objects_causing_outdatedness_of(base_item) }.from([]).to([document])
end
it 'creates a dependency with the right props' do
subject
dep = dependency_store.dependencies_causing_outdatedness_of(base_item)[0]
expect(dep.props.attributes?).to eq(true)
expect(dep.props.raw_content?).to eq(false)
expect(dep.props.compiled_content?).to eq(false)
expect(dep.props.path?).to eq(false)
end
it 'returns attributes' do
expect(subject).to eql(animal: 'donkey')
end
end
describe '#fetch' do
let(:document) { entity_class.new('stuff', { animal: 'donkey' }, '/foo') }
context 'with existant key' do
let(:key) { :animal }
subject { view.fetch(key) }
it { is_expected.to eql('donkey') }
it 'creates a dependency' do
expect { subject }.to change { dependency_store.objects_causing_outdatedness_of(base_item) }.from([]).to([document])
end
it 'creates a dependency with the right props' do
subject
dep = dependency_store.dependencies_causing_outdatedness_of(base_item)[0]
expect(dep.props.attributes?).to eq(true)
expect(dep.props.raw_content?).to eq(false)
expect(dep.props.compiled_content?).to eq(false)
expect(dep.props.path?).to eq(false)
end
end
context 'with non-existant key' do
let(:key) { :weapon }
context 'with fallback' do
subject { view.fetch(key, 'nothing sorry') }
it { is_expected.to eql('nothing sorry') }
it 'creates a dependency' do
expect { subject }.to change { dependency_store.objects_causing_outdatedness_of(base_item) }.from([]).to([document])
end
it 'creates a dependency with the right props' do
subject
dep = dependency_store.dependencies_causing_outdatedness_of(base_item)[0]
expect(dep.props.attributes?).to eq(true)
expect(dep.props.raw_content?).to eq(false)
expect(dep.props.compiled_content?).to eq(false)
expect(dep.props.path?).to eq(false)
end
end
context 'with block' do
subject { view.fetch(key) { 'nothing sorry' } }
it { is_expected.to eql('nothing sorry') }
it 'creates a dependency' do
expect { subject }.to change { dependency_store.objects_causing_outdatedness_of(base_item) }.from([]).to([document])
end
it 'creates a dependency with the right props' do
subject
dep = dependency_store.dependencies_causing_outdatedness_of(base_item)[0]
expect(dep.props.attributes?).to eq(true)
expect(dep.props.raw_content?).to eq(false)
expect(dep.props.compiled_content?).to eq(false)
expect(dep.props.path?).to eq(false)
end
end
context 'with no fallback and no block' do
subject { view.fetch(key) }
it 'raises' do
expect { subject }.to raise_error(KeyError)
end
end
end
end
describe '#key?' do
let(:document) { entity_class.new('stuff', { animal: 'donkey' }, '/foo') }
subject { view.key?(key) }
context 'with existant key' do
let(:key) { :animal }
it { is_expected.to eql(true) }
it 'creates a dependency' do
expect { subject }.to change { dependency_store.objects_causing_outdatedness_of(base_item) }.from([]).to([document])
end
it 'creates a dependency with the right props' do
subject
dep = dependency_store.dependencies_causing_outdatedness_of(base_item)[0]
expect(dep.props.attributes?).to eq(true)
expect(dep.props.raw_content?).to eq(false)
expect(dep.props.compiled_content?).to eq(false)
expect(dep.props.path?).to eq(false)
end
end
context 'with non-existant key' do
let(:key) { :weapon }
it { is_expected.to eql(false) }
it 'creates a dependency' do
expect { subject }.to change { dependency_store.objects_causing_outdatedness_of(base_item) }.from([]).to([document])
end
it 'creates a dependency with the right props' do
subject
dep = dependency_store.dependencies_causing_outdatedness_of(base_item)[0]
expect(dep.props.attributes?).to eq(true)
expect(dep.props.raw_content?).to eq(false)
expect(dep.props.compiled_content?).to eq(false)
expect(dep.props.path?).to eq(false)
end
end
end
describe '#hash' do
let(:document) { double(:document, identifier: '/foo') }
subject { view.hash }
it { should == described_class.hash ^ '/foo'.hash }
end
describe '#raw_content' do
let(:document) { entity_class.new('stuff', { animal: 'donkey' }, '/foo') }
subject { view.raw_content }
it { is_expected.to eql('stuff') }
it 'creates a dependency' do
expect { subject }.to change { dependency_store.objects_causing_outdatedness_of(base_item) }.from([]).to([document])
end
it 'creates a dependency with the right props' do
subject
dep = dependency_store.dependencies_causing_outdatedness_of(base_item)[0]
expect(dep.props.raw_content?).to eq(true)
expect(dep.props.attributes?).to eq(false)
expect(dep.props.compiled_content?).to eq(false)
expect(dep.props.path?).to eq(false)
end
end
end
nanoc-4.11.0/nanoc/spec/nanoc/base/views/support/identifiable_collection_view_examples.rb000066400000000000000000000172701340050175000317150ustar00rootroot00000000000000# frozen_string_literal: true
# Needs :view_class
shared_examples 'an identifiable collection view' do
let(:view) { described_class.new(wrapped, view_context) }
let(:view_context) do
Nanoc::ViewContextForCompilation.new(
reps: Nanoc::Int::ItemRepRepo.new,
items: Nanoc::Int::ItemCollection.new(config),
dependency_tracker: dependency_tracker,
compilation_context: double(:__compilation_context),
snapshot_repo: double(:__snapshot_repo),
)
end
let(:dependency_tracker) do
Nanoc::Int::DependencyTracker::Null.new
end
let(:config) do
{ string_pattern_type: 'glob' }
end
describe '#frozen?' do
let(:wrapped) do
collection_class.new(
config,
[
double(:identifiable, identifier: Nanoc::Identifier.new('/foo')),
double(:identifiable, identifier: Nanoc::Identifier.new('/bar')),
],
)
end
subject { view.frozen? }
context 'non-frozen collection' do
it { is_expected.to be(false) }
end
context 'frozen collection' do
before do
wrapped.each { |o| expect(o).to receive(:freeze) }
wrapped.freeze
end
it { is_expected.to be(true) }
end
end
describe '#_unwrap' do
let(:wrapped) do
collection_class.new(
config,
[
double(:identifiable, identifier: Nanoc::Identifier.new('/foo')),
double(:identifiable, identifier: Nanoc::Identifier.new('/bar')),
double(:identifiable, identifier: Nanoc::Identifier.new('/baz')),
],
)
end
subject { view._unwrap }
it { should equal(wrapped) }
it 'does not create dependency' do
expect(dependency_tracker).not_to receive(:bounce)
subject
end
end
describe '#each' do
let(:wrapped) do
collection_class.new(
config,
[
double(:identifiable, identifier: Nanoc::Identifier.new('/foo')),
double(:identifiable, identifier: Nanoc::Identifier.new('/bar')),
double(:identifiable, identifier: Nanoc::Identifier.new('/baz')),
],
)
end
it 'creates dependency' do
expect(dependency_tracker).to receive(:bounce).with(wrapped, raw_content: true)
view.each { |_i| }
end
it 'returns self' do
expect(view.each { |_i| }).to equal(view)
end
it 'yields elements with the right context' do
view.each { |v| expect(v._context).to equal(view_context) }
end
end
describe '#size' do
let(:wrapped) do
collection_class.new(
config,
[
double(:identifiable, identifier: Nanoc::Identifier.new('/foo')),
double(:identifiable, identifier: Nanoc::Identifier.new('/bar')),
double(:identifiable, identifier: Nanoc::Identifier.new('/baz')),
],
)
end
subject { view.size }
it 'creates dependency' do
expect(dependency_tracker).to receive(:bounce).with(wrapped, raw_content: true)
subject
end
it { should == 3 }
end
describe '#[]' do
let(:page_object) do
double(:identifiable, identifier: Nanoc::Identifier.new('/page.erb'))
end
let(:home_object) do
double(:identifiable, identifier: Nanoc::Identifier.new('/home.erb'))
end
let(:wrapped) do
collection_class.new(
config,
[
page_object,
home_object,
],
)
end
subject { view[arg] }
context 'no objects found' do
let(:arg) { '/donkey.*' }
it { is_expected.to equal(nil) }
it 'creates dependency' do
expect(dependency_tracker).to receive(:bounce).with(wrapped, raw_content: ['/donkey.*'])
subject
end
end
context 'string' do
let(:arg) { '/home.erb' }
it 'creates dependency' do
expect(dependency_tracker).to receive(:bounce).with(wrapped, raw_content: ['/home.erb'])
subject
end
it 'returns wrapped object' do
expect(subject.class).to equal(view_class)
expect(subject._unwrap).to equal(home_object)
end
it 'returns objects with right context' do
expect(subject._context).to equal(view_context)
end
end
context 'identifier' do
let(:arg) { Nanoc::Identifier.new('/home.erb') }
it 'creates dependency' do
expect(dependency_tracker).to receive(:bounce).with(wrapped, raw_content: ['/home.erb'])
subject
end
it 'returns wrapped object' do
expect(subject.class).to equal(view_class)
expect(subject._unwrap).to equal(home_object)
end
end
context 'glob' do
let(:arg) { '/home.*' }
context 'globs not enabled' do
let(:config) { { string_pattern_type: 'legacy' } }
it 'creates dependency' do
expect(dependency_tracker).to receive(:bounce).with(wrapped, raw_content: ['/home.*'])
subject
end
it 'returns nil' do
expect(subject).to be_nil
end
end
context 'globs enabled' do
it 'creates dependency' do
expect(dependency_tracker).to receive(:bounce).with(wrapped, raw_content: ['/home.*'])
subject
end
it 'returns wrapped object' do
expect(subject.class).to equal(view_class)
expect(subject._unwrap).to equal(home_object)
end
end
end
context 'regex' do
let(:arg) { %r{\A/home} }
it 'creates dependency' do
expect(dependency_tracker).to receive(:bounce).with(wrapped, raw_content: [%r{\A/home}])
subject
end
it 'returns wrapped object' do
expect(subject.class).to equal(view_class)
expect(subject._unwrap).to equal(home_object)
end
end
end
describe '#find_all' do
let(:wrapped) do
collection_class.new(
config,
[
double(:identifiable, identifier: Nanoc::Identifier.new('/about.css')),
double(:identifiable, identifier: Nanoc::Identifier.new('/about.md')),
double(:identifiable, identifier: Nanoc::Identifier.new('/style.css')),
],
)
end
context 'with string' do
subject { view.find_all('/*.css') }
it 'creates dependency' do
expect(dependency_tracker).to receive(:bounce).with(wrapped, raw_content: ['/*.css'])
subject
end
it 'contains views' do
expect(subject.size).to eql(2)
about_css = subject.find { |iv| iv.identifier == '/about.css' }
style_css = subject.find { |iv| iv.identifier == '/style.css' }
expect(about_css.class).to equal(view_class)
expect(style_css.class).to equal(view_class)
end
end
context 'with regex' do
subject { view.find_all(%r{\.css\z}) }
it 'creates dependency' do
expect(dependency_tracker).to receive(:bounce).with(wrapped, raw_content: [%r{\.css\z}])
subject
end
it 'contains views' do
expect(subject.size).to eql(2)
about_css = subject.find { |iv| iv.identifier == '/about.css' }
style_css = subject.find { |iv| iv.identifier == '/style.css' }
expect(about_css.class).to equal(view_class)
expect(style_css.class).to equal(view_class)
end
end
context 'with block' do
subject { view.find_all { |iv| iv.identifier =~ /css/ } }
it 'creates dependency' do
expect(dependency_tracker).to receive(:bounce).with(wrapped, raw_content: true)
subject
end
it 'contains views' do
expect(subject.size).to eql(2)
about_css = subject.find { |iv| iv.identifier == '/about.css' }
style_css = subject.find { |iv| iv.identifier == '/style.css' }
expect(about_css.class).to equal(view_class)
expect(style_css.class).to equal(view_class)
end
end
end
end
nanoc-4.11.0/nanoc/spec/nanoc/base/views/support/item_rep_collection_view_examples.rb000066400000000000000000000062551340050175000311030ustar00rootroot00000000000000# frozen_string_literal: true
shared_examples 'an item rep collection view' do
let(:view) { described_class.new(wrapped, view_context) }
let(:view_context) { double(:view_context) }
let(:wrapped) do
[
double(:item_rep, name: :foo),
double(:item_rep, name: :bar),
double(:item_rep, name: :baz),
]
end
describe '#_unwrap' do
subject { view._unwrap }
it { should equal(wrapped) }
end
describe '#frozen?' do
subject { view.frozen? }
context 'non-frozen collection' do
it { is_expected.to be(false) }
end
context 'frozen collection' do
before { wrapped.freeze }
it { is_expected.to be(true) }
end
end
describe '#each' do
it 'yields' do
actual = [].tap { |res| view.each { |v| res << v } }
expect(actual.size).to eq(3)
end
it 'returns self' do
expect(view.each { |_i| }).to equal(view)
end
it 'yields elements with the right context' do
view.each { |v| expect(v._context).to equal(view_context) }
end
end
describe '#size' do
subject { view.size }
it { should == 3 }
end
describe '#to_ary' do
subject { view.to_ary }
it 'returns an array of item rep views' do
expect(subject.class).to eq(Array)
expect(subject.size).to eq(3)
expect(subject[0].class).to eql(expected_view_class)
expect(subject[0].name).to eql(:foo)
end
it 'returns an array with correct contexts' do
expect(subject[0]._context).to equal(view_context)
end
end
describe '#[]' do
subject { view[name] }
context 'when not found' do
let(:name) { :donkey }
it { should be_nil }
end
context 'when found' do
let(:name) { :foo }
it 'returns a view' do
expect(subject.class).to eq(expected_view_class)
expect(subject.name).to eq(:foo)
end
it 'returns a view with the correct context' do
expect(subject._context).to equal(view_context)
end
end
context 'when given a string' do
let(:name) { 'foo' }
it 'raises' do
expect { subject }.to raise_error(ArgumentError, 'expected BasicItemRepCollectionView#[] to be called with a symbol')
end
end
context 'when given a number' do
let(:name) { 0 }
it 'raises' do
expect { subject }.to raise_error(ArgumentError, 'expected BasicItemRepCollectionView#[] to be called with a symbol (you likely want `.reps[:default]` rather than `.reps[0]`)')
end
end
end
describe '#fetch' do
subject { view.fetch(name) }
context 'when not found' do
let(:name) { :donkey }
it 'raises' do
expect { subject }.to raise_error(Nanoc::BasicItemRepCollectionView::NoSuchItemRepError)
end
end
context 'when found' do
let(:name) { :foo }
it 'returns a view' do
expect(subject.class).to eq(expected_view_class)
expect(subject.name).to eq(:foo)
end
it 'returns a view with the correct context' do
expect(subject._context).to equal(view_context)
end
end
end
describe '#inspect' do
subject { view.inspect }
it { is_expected.to eql('<' + described_class.name + '>') }
end
end
nanoc-4.11.0/nanoc/spec/nanoc/base/views/support/item_rep_view_examples.rb000066400000000000000000000214731340050175000266670ustar00rootroot00000000000000# frozen_string_literal: true
shared_examples 'an item rep view' do
# needs expected_item_view_class
let(:view_context) do
Nanoc::ViewContextForCompilation.new(
reps: Nanoc::Int::ItemRepRepo.new,
items: Nanoc::Int::ItemCollection.new(config),
dependency_tracker: dependency_tracker,
compilation_context: compilation_context,
snapshot_repo: snapshot_repo,
)
end
let(:compilation_context) { double(:compilation_context) }
let(:snapshot_repo) { Nanoc::Int::SnapshotRepo.new }
let(:dependency_tracker) { Nanoc::Int::DependencyTracker.new(dependency_store) }
let(:dependency_store) { Nanoc::Int::DependencyStore.new(empty_items, empty_layouts, config) }
let(:base_item) { Nanoc::Int::Item.new('base', {}, '/base.md') }
let(:empty_items) { Nanoc::Int::ItemCollection.new(config) }
let(:empty_layouts) { Nanoc::Int::LayoutCollection.new(config) }
let(:config) { Nanoc::Int::Configuration.new(dir: Dir.getwd).with_defaults }
before do
dependency_tracker.enter(base_item)
end
describe '#frozen?' do
let(:item_rep) { Nanoc::Int::ItemRep.new(item, :jacques) }
let(:item) { Nanoc::Int::Item.new('asdf', {}, '/foo') }
let(:view) { described_class.new(item_rep, view_context) }
subject { view.frozen? }
context 'non-frozen item rep' do
it { is_expected.to be(false) }
end
context 'frozen item rep' do
before { item_rep.freeze }
it { is_expected.to be(true) }
end
end
describe '#== and #eql?' do
let(:item_rep) { Nanoc::Int::ItemRep.new(item, :jacques) }
let(:item) { Nanoc::Int::Item.new('asdf', {}, '/foo') }
let(:view) { described_class.new(item_rep, view_context) }
context 'comparing with item rep with same identifier' do
let(:other_item) { double(:other_item, identifier: '/foo') }
let(:other) { double(:other_item_rep, item: other_item, name: :jacques) }
it 'is ==' do
expect(view).to eq(other)
end
it 'is eql?' do
expect(view).not_to eql(other)
end
end
context 'comparing with item rep with different identifier' do
let(:other_item) { double(:other_item, identifier: '/bar') }
let(:other) { double(:other_item_rep, item: other_item, name: :jacques) }
it 'is not ==' do
expect(view).not_to eq(other)
end
it 'is not eql?' do
expect(view).not_to eql(other)
end
end
context 'comparing with item rep with different name' do
let(:other_item) { double(:other_item, identifier: '/foo') }
let(:other) { double(:other_item_rep, item: other_item, name: :marvin) }
it 'is not ==' do
expect(view).not_to eq(other)
end
it 'is not eql?' do
expect(view).not_to eql(other)
end
end
context 'comparing with item rep with same identifier' do
let(:other_item) { double(:other_item, identifier: '/foo') }
let(:other) { described_class.new(double(:other_item_rep, item: other_item, name: :jacques), view_context) }
it 'is ==' do
expect(view).to eq(other)
end
it 'is eql?' do
expect(view).not_to eql(other)
end
end
context 'comparing with item rep with different identifier' do
let(:other_item) { double(:other_item, identifier: '/bar') }
let(:other) { described_class.new(double(:other_item_rep, item: other_item, name: :jacques), view_context) }
it 'is not equal' do
expect(view).not_to eq(other)
expect(view).not_to eql(other)
end
end
context 'comparing with item rep with different name' do
let(:other_item) { double(:other_item, identifier: '/foo') }
let(:other) { described_class.new(double(:other_item_rep, item: other_item, name: :marvin), view_context) }
it 'is not equal' do
expect(view).not_to eq(other)
expect(view).not_to eql(other)
end
end
context 'comparing with something that is not an item rep' do
let(:other_item) { double(:other_item, identifier: '/foo') }
let(:other) { :donkey }
it 'is not equal' do
expect(view).not_to eq(other)
expect(view).not_to eql(other)
end
end
end
describe '#hash' do
let(:item_rep) { Nanoc::Int::ItemRep.new(item, :jacques) }
let(:item) { Nanoc::Int::Item.new('asdf', {}, '/foo') }
let(:view) { described_class.new(item_rep, view_context) }
subject { view.hash }
it { should == described_class.hash ^ Nanoc::Identifier.new('/foo').hash ^ :jacques.hash }
end
describe '#snapshot?' do
subject { view.snapshot?(snapshot_name) }
let(:view) { described_class.new(rep, view_context) }
let(:rep) do
Nanoc::Int::ItemRep.new(item, :default).tap do |ir|
ir.compiled = true
ir.snapshot_defs = [
Nanoc::Int::SnapshotDef.new(:last, binary: false),
]
end
end
let(:item) do
Nanoc::Int::Item.new('content', {}, '/asdf.md')
end
let(:snapshot_name) { raise 'override me' }
before do
snapshot_repo.set(rep, :last, Nanoc::Int::TextualContent.new('Hallo'))
end
context 'snapshot exists' do
let(:snapshot_name) { :last }
it 'creates a dependency' do
expect { subject }.to change { dependency_store.objects_causing_outdatedness_of(base_item) }.from([]).to([item])
end
it 'creates a dependency with the right props' do
subject
dep = dependency_store.dependencies_causing_outdatedness_of(base_item)[0]
expect(dep.props.compiled_content?).to eq(true)
expect(dep.props.raw_content?).to eq(false)
expect(dep.props.attributes?).to eq(false)
expect(dep.props.path?).to eq(false)
end
it { is_expected.to be }
end
context 'snapshot does not exist' do
let(:snapshot_name) { :donkey }
it 'creates a dependency' do
expect { subject }.to change { dependency_store.objects_causing_outdatedness_of(base_item) }.from([]).to([item])
end
it 'creates a dependency with the right props' do
subject
dep = dependency_store.dependencies_causing_outdatedness_of(base_item)[0]
expect(dep.props.compiled_content?).to eq(true)
expect(dep.props.raw_content?).to eq(false)
expect(dep.props.attributes?).to eq(false)
expect(dep.props.path?).to eq(false)
end
it { is_expected.not_to be }
end
end
describe '#path' do
subject { view.path }
let(:view) { described_class.new(rep, view_context) }
let(:rep) do
Nanoc::Int::ItemRep.new(item, :default).tap do |ir|
ir.paths = {
last: ['/about/'],
}
end
end
let(:item) do
Nanoc::Int::Item.new('content', {}, '/asdf.md')
end
it 'creates a dependency' do
expect { subject }.to change { dependency_store.objects_causing_outdatedness_of(base_item) }.from([]).to([item])
end
it 'creates a dependency with the right props' do
subject
dep = dependency_store.dependencies_causing_outdatedness_of(base_item)[0]
expect(dep.props.path?).to eq(true)
expect(dep.props.raw_content?).to eq(false)
expect(dep.props.attributes?).to eq(false)
expect(dep.props.compiled_content?).to eq(false)
end
it { should eq('/about/') }
end
describe '#binary?' do
let(:item_rep) { Nanoc::Int::ItemRep.new(item, :jacques) }
let(:item) { Nanoc::Int::Item.new('asdf', {}, '/foo') }
let(:view) { described_class.new(item_rep, view_context) }
subject { view.binary? }
context 'no :last snapshot' do
before do
item_rep.snapshot_defs = []
end
it 'raises' do
expect { subject }.to raise_error(Nanoc::Int::Errors::NoSuchSnapshot)
end
end
context ':last snapshot is textual' do
before do
item_rep.snapshot_defs = [Nanoc::Int::SnapshotDef.new(:last, binary: false)]
end
it { is_expected.not_to be }
end
context ':last snapshot is binary' do
before do
item_rep.snapshot_defs = [Nanoc::Int::SnapshotDef.new(:last, binary: true)]
end
it { is_expected.to be }
end
end
describe '#item' do
let(:item_rep) { Nanoc::Int::ItemRep.new(item, :jacques) }
let(:item) { Nanoc::Int::Item.new('asdf', {}, '/foo') }
let(:view) { described_class.new(item_rep, view_context) }
subject { view.item }
it 'returns an item view' do
expect(subject).to be_a(expected_item_view_class)
end
it 'returns an item view with the right context' do
expect(subject._context).to equal(view_context)
end
end
describe '#inspect' do
let(:item_rep) { Nanoc::Int::ItemRep.new(item, :jacques) }
let(:item) { Nanoc::Int::Item.new('asdf', {}, '/foo') }
let(:view) { described_class.new(item_rep, view_context) }
subject { view.inspect }
it { is_expected.to eql('<' + described_class.to_s + ' item.identifier=/foo name=jacques>') }
end
end
nanoc-4.11.0/nanoc/spec/nanoc/base/views/support/mutable_document_view_examples.rb000066400000000000000000000130651340050175000304100ustar00rootroot00000000000000# frozen_string_literal: true
shared_examples 'a mutable document view' do
let(:view) { described_class.new(document, view_context) }
let(:view_context) do
Nanoc::ViewContextForCompilation.new(
reps: Nanoc::Int::ItemRepRepo.new,
items: Nanoc::Int::ItemCollection.new(config),
dependency_tracker: dependency_tracker,
compilation_context: double(:compilation_context),
snapshot_repo: snapshot_repo,
)
end
let(:dependency_tracker) { Nanoc::Int::DependencyTracker.new(double(:dependency_store)) }
let(:snapshot_repo) { double(:snapshot_repo) }
let(:config) { Nanoc::Int::Configuration.new(dir: Dir.getwd) }
describe '#raw_content=' do
let(:document) { entity_class.new('content', {}, '/asdf') }
it 'sets raw content' do
expect { view.raw_content = 'donkey' }
.to change { document.content.string }
.from('content')
.to('donkey')
end
context 'checksum_data set' do
before do
document.checksum_data = 'my checksum data'
document.content_checksum_data = 'my content checksum data'
document.attributes_checksum_data = 'my attributes checksum data'
end
it 'unsets checksum_data' do
expect { view.raw_content = 'donkey' }
.to change { document.checksum_data }
.from('my checksum data')
.to(nil)
end
it 'unsets content_checksum_data' do
expect { view.raw_content = 'donkey' }
.to change { document.content_checksum_data }
.from('my content checksum data')
.to(nil)
end
it 'keeps attributes_checksum_data' do
expect { view.raw_content = 'donkey' }
.not_to change { document.attributes_checksum_data }
end
end
end
describe '#[]=' do
let(:document) { entity_class.new('content', {}, '/asdf') }
it 'sets attributes' do
view[:title] = 'Donkey'
expect(view[:title]).to eq('Donkey')
end
it 'disallows items' do
item = Nanoc::Int::Item.new('content', {}, '/foo.md')
expect { view[:item] = item }.to raise_error(Nanoc::MutableDocumentViewMixin::DisallowedAttributeValueError)
end
it 'disallows layouts' do
layout = Nanoc::Int::Layout.new('content', {}, '/foo.md')
expect { view[:layout] = layout }.to raise_error(Nanoc::MutableDocumentViewMixin::DisallowedAttributeValueError)
end
it 'disallows item views' do
item = Nanoc::CompilationItemView.new(Nanoc::Int::Item.new('content', {}, '/foo.md'), nil)
expect { view[:item] = item }.to raise_error(Nanoc::MutableDocumentViewMixin::DisallowedAttributeValueError)
end
it 'disallows layout views' do
layout = Nanoc::LayoutView.new(Nanoc::Int::Layout.new('content', {}, '/foo.md'), nil)
expect { view[:layout] = layout }.to raise_error(Nanoc::MutableDocumentViewMixin::DisallowedAttributeValueError)
end
context 'checksum_data set' do
before do
document.checksum_data = 'my checksum data'
document.content_checksum_data = 'my content checksum data'
document.attributes_checksum_data = 'my attributes checksum data'
end
it 'unsets checksum_data' do
expect { view[:title] = 'Donkey' }
.to change { document.checksum_data }
.from('my checksum data')
.to(nil)
end
it 'unsets attributes_checksum_data' do
expect { view[:title] = 'Donkey' }
.to change { document.attributes_checksum_data }
.from('my attributes checksum data')
.to(nil)
end
it 'keeps content_checksum_data' do
expect { view[:title] = 'Donkey' }
.not_to change { document.content_checksum_data }
end
end
end
describe '#identifier=' do
let(:document) { entity_class.new('content', {}, '/about.md') }
subject { view.identifier = arg }
context 'given a string' do
let(:arg) { '/about.adoc' }
it 'changes the identifier' do
subject
expect(view.identifier).to eq('/about.adoc')
end
end
context 'given an identifier' do
let(:arg) { Nanoc::Identifier.new('/about.adoc') }
it 'changes the identifier' do
subject
expect(view.identifier).to eq('/about.adoc')
end
end
context 'given anything else' do
let(:arg) { :donkey }
it 'raises' do
expect { subject }.to raise_error(Nanoc::Identifier::NonCoercibleObjectError)
end
end
end
describe '#update_attributes' do
let(:document) { entity_class.new('content', {}, '/asdf') }
let(:update) { { friend: 'Giraffe' } }
subject { view.update_attributes(update) }
it 'sets attributes' do
expect { subject }.to change { view[:friend] }.from(nil).to('Giraffe')
end
it 'returns self' do
expect(subject).to equal(view)
end
context 'checksum_data set' do
before do
document.checksum_data = 'my checksum data'
document.content_checksum_data = 'my content checksum data'
document.attributes_checksum_data = 'my attributes checksum data'
end
it 'unsets checksum_data' do
expect { subject }
.to change { document.checksum_data }
.from('my checksum data')
.to(nil)
end
it 'unsets attributes_checksum_data' do
expect { subject }
.to change { document.attributes_checksum_data }
.from('my attributes checksum data')
.to(nil)
end
it 'keeps content_checksum_data' do
expect { subject }
.not_to change { document.content_checksum_data }
end
end
end
end
nanoc-4.11.0/nanoc/spec/nanoc/base/views/support/mutable_identifiable_collection_view_examples.rb000066400000000000000000000020431340050175000334160ustar00rootroot00000000000000# frozen_string_literal: true
shared_examples 'a mutable identifiable collection view' do
let(:view) { described_class.new(wrapped, view_context) }
let(:view_context) { double(:view_context) }
let(:config) do
{}
end
describe '#delete_if' do
let(:wrapped) do
collection_class.new(
config,
[double(:identifiable, identifier: Nanoc::Identifier.new('/asdf'))],
)
end
it 'deletes matching' do
view.delete_if { |i| i.identifier == '/asdf' }
expect(view._unwrap).to be_empty
end
it 'does not mutate' do
view.delete_if { |i| i.identifier == '/asdf' }
expect(wrapped).not_to be_empty
end
it 'deletes no non-matching' do
view.delete_if { |i| i.identifier == '/blah' }
expect(wrapped).not_to be_empty
end
it 'returns self' do
ret = view.delete_if { |_i| false }
expect(ret).to equal(view)
end
it 'yields items with the proper context' do
view.delete_if { |i| expect(i._context).to equal(view_context) }
end
end
end
nanoc-4.11.0/nanoc/spec/nanoc/checking/000077500000000000000000000000001340050175000175675ustar00rootroot00000000000000nanoc-4.11.0/nanoc/spec/nanoc/checking/check_spec.rb000066400000000000000000000043061340050175000222060ustar00rootroot00000000000000# frozen_string_literal: true
describe Nanoc::Check do
it 'is an alias' do
expect(described_class).to equal(Nanoc::Checking::Check)
end
end
describe Nanoc::Checking::Check do
describe '.define' do
before do
described_class.define(:spec_check_example_1) do
add_issue('it’s totes bad')
end
end
let(:site) do
Nanoc::Int::Site.new(
config: config,
code_snippets: code_snippets,
data_source: Nanoc::Int::InMemDataSource.new(items, layouts),
)
end
let(:config) { Nanoc::Int::Configuration.new(dir: Dir.getwd).with_defaults }
let(:code_snippets) { [] }
let(:items) { Nanoc::Int::ItemCollection.new(config, []) }
let(:layouts) { Nanoc::Int::LayoutCollection.new(config, []) }
before do
FileUtils.mkdir_p('output')
File.write('Rules', 'passthrough "/**/*"')
end
it 'is discoverable' do
expect(described_class.named(:spec_check_example_1)).not_to be_nil
end
it 'runs properly' do
check = described_class.named(:spec_check_example_1).create(site)
check.run
expect(check.issues.size).to eq(1)
expect(check.issues.first.description).to eq('it’s totes bad')
end
end
describe '.named' do
it 'finds checks that exist' do
expect(described_class.named(:internal_links)).not_to be_nil
end
it 'is nil for non-existent checks' do
expect(described_class.named(:asdfaskjlfdalhsgdjf)).to be_nil
end
end
describe '#output_html_filenames' do
let(:check) do
described_class.new(output_filenames: output_filenames)
end
let(:output_filenames) do
[
'output/foo.html',
'output/foo.htm',
'output/foo.xhtml',
'output/foo.txt',
'output/foo.htmlx',
'output/foo.yhtml',
]
end
subject { check.output_html_filenames }
it { is_expected.to include('output/foo.html') }
it { is_expected.to include('output/foo.htm') }
it { is_expected.to include('output/foo.xhtml') }
it { is_expected.not_to include('output/foo.txt') }
it { is_expected.not_to include('output/foo.htmlx') }
it { is_expected.not_to include('output/foo.yhtml') }
end
end
nanoc-4.11.0/nanoc/spec/nanoc/checking/checks/000077500000000000000000000000001340050175000210275ustar00rootroot00000000000000nanoc-4.11.0/nanoc/spec/nanoc/checking/checks/external_links_spec.rb000066400000000000000000000064541340050175000254210ustar00rootroot00000000000000# frozen_string_literal: true
describe ::Nanoc::Checking::Checks::ExternalLinks do
let(:check) do
Nanoc::Checking::Checks::ExternalLinks.create(site).tap do |c|
def c.request_url_once(_url)
Net::HTTPResponse.new('1.1', '200', 'okay')
end
end
end
let(:site) do
Nanoc::Int::Site.new(
config: config,
code_snippets: code_snippets,
data_source: Nanoc::Int::InMemDataSource.new(items, layouts),
)
end
let(:config) { Nanoc::Int::Configuration.new(dir: Dir.getwd).with_defaults }
let(:code_snippets) { [] }
let(:items) { Nanoc::Int::ItemCollection.new(config, []) }
let(:layouts) { Nanoc::Int::LayoutCollection.new(config, []) }
before do
FileUtils.mkdir_p('output')
File.write('output/hi.html', ' stuff')
File.write('Rules', 'passthrough "/**/*"')
end
context 'found' do
let(:check) do
Nanoc::Checking::Checks::ExternalLinks.create(site).tap do |c|
def c.request_url_once(_url)
Net::HTTPResponse.new('1.1', '200', 'okay')
end
end
end
it 'has no issues' do
check.run
expect(check.issues).to be_empty
end
end
context 'not found' do
let(:check) do
Nanoc::Checking::Checks::ExternalLinks.create(site).tap do |c|
def c.request_url_once(_url)
Net::HTTPResponse.new('1.1', '404', 'okay')
end
end
end
it 'has issues' do
check.run
expect(check.issues.size).to eq(1)
end
end
context 'redirect' do
before do
skip 'Known failure on Windows' if Nanoc.on_windows?
end
let(:check) do
Nanoc::Checking::Checks::ExternalLinks.create(site).tap do |c|
def c.request_url_once(_url)
@enum ||= Enumerator.new do |y|
y << Net::HTTPResponse.new('1.1', '302', 'look elsewhere').tap do |h|
h['Location'] = 'http://elsewhere.example.com/'
end
y << Net::HTTPResponse.new('1.1', '200', 'okay')
end
@enum.next
end
end
end
it 'has no issues' do
check.run
expect(check.issues).to be_empty
end
end
context 'redirect without location' do
before do
skip 'Known failure on Windows' if Nanoc.on_windows?
end
let(:check) do
Nanoc::Checking::Checks::ExternalLinks.create(site).tap do |c|
def c.request_url_once(_url)
@enum ||= Enumerator.new do |y|
y << Net::HTTPResponse.new('1.1', '302', 'look elsewhere')
end
@enum.next
end
end
end
it 'has issues' do
check.run
expect(check.issues.size).to eq(1)
expect(check.issues.first.description)
.to eq('broken reference to http://example.com/x: redirection without a target location')
end
end
context 'invalid URL component' do
before do
skip 'Known failure on Windows' if Nanoc.on_windows?
end
let(:check) do
Nanoc::Checking::Checks::ExternalLinks.create(site)
end
before do
File.write('output/hi.html', 'stuff')
end
it 'has issues' do
check.run
expect(check.issues.size).to eq(1)
expect(check.issues.first.description)
.to eq('broken reference to mailto:lol: invalid URI')
end
end
end
nanoc-4.11.0/nanoc/spec/nanoc/checking/runner_spec.rb000066400000000000000000000066731340050175000224530ustar00rootroot00000000000000# frozen_string_literal: true
describe Nanoc::Checking::Runner, site: true do
subject(:runner) { described_class.new(site) }
let(:site) { Nanoc::Int::SiteLoader.new.new_from_cwd }
describe '#any_enabled_checks?' do
subject { runner.any_enabled_checks? }
context 'no DSL' do
context 'no deploy checks defined in config' do
it { is_expected.to be(false) }
end
context 'deploy checks defined in config' do
before do
File.write('nanoc.yaml', "checking:\n enabled_checks:\n - elinks")
end
it { is_expected.to be(true) }
end
end
context 'DSL without deploy checks defined' do
before do
File.write('Checks', '')
end
context 'no deploy checks defined in config' do
it { is_expected.to be(false) }
end
context 'deploy checks defined in config' do
before do
File.write('nanoc.yaml', "checking:\n enabled_checks:\n - elinks")
end
it { is_expected.to be(true) }
end
end
context 'DSL with deploy checks defined' do
before do
File.write('Checks', 'deploy_check :ilinks')
end
context 'no deploy checks defined in config' do
it { is_expected.to be(true) }
end
context 'deploy checks defined in config' do
before do
File.write('nanoc.yaml', "checking:\n enabled_checks:\n - elinks")
end
it { is_expected.to be(true) }
end
end
end
describe '#enabled_checks' do
subject { runner.send(:enabled_checks) }
context 'no DSL' do
context 'no deploy checks defined in config' do
it { is_expected.to be_empty }
end
context 'deploy checks defined in config' do
before do
File.write('nanoc.yaml', "checking:\n enabled_checks:\n - elinks")
end
it { is_expected.to match_array([:elinks]) }
end
end
context 'DSL without deploy checks defined' do
before do
File.write('Checks', '')
end
context 'no deploy checks defined in config' do
it { is_expected.to be_empty }
end
context 'deploy checks defined in config' do
before do
File.write('nanoc.yaml', "checking:\n enabled_checks:\n - elinks")
end
it { is_expected.to match_array([:elinks]) }
end
end
context 'DSL with deploy checks defined' do
before do
File.write('Checks', 'deploy_check :ilinks')
end
context 'no deploy checks defined in config' do
it { is_expected.to match_array([:ilinks]) }
end
context 'deploy checks defined in config' do
before do
File.write('nanoc.yaml', "checking:\n enabled_checks:\n - elinks")
end
it { is_expected.to match_array(%i[ilinks elinks]) }
end
end
end
describe '#check_classes_named' do
subject { runner.send(:check_classes_named, names) }
context 'given one full name' do
let(:names) { %w[internal_links] }
it { is_expected.to eq([Nanoc::Checking::Checks::InternalLinks]) }
end
context 'given one full name with dash instead of underscore' do
let(:names) { %w[internal-links] }
it { is_expected.to eq([Nanoc::Checking::Checks::InternalLinks]) }
end
context 'given one abbreviated name' do
let(:names) { %w[ilinks] }
it { is_expected.to eq([Nanoc::Checking::Checks::InternalLinks]) }
end
end
end
nanoc-4.11.0/nanoc/spec/nanoc/cli/000077500000000000000000000000001340050175000165635ustar00rootroot00000000000000nanoc-4.11.0/nanoc/spec/nanoc/cli/command_runner_spec.rb000066400000000000000000000053021340050175000231310ustar00rootroot00000000000000# frozen_string_literal: true
describe Nanoc::CLI::CommandRunner, stdio: true do
describe '.find_site_dir' do
subject { described_class.find_site_dir }
context 'config file in current dir' do
before { File.write('nanoc.yaml', 'hi') }
it 'returns the current dir' do
expect(subject).to eq(File.expand_path(Dir.getwd))
end
end
context 'config file in parent dir' do
around do |ex|
FileUtils.mkdir_p('root/sub')
File.write('root/nanoc.yaml', 'hi')
chdir('root/sub') { ex.run }
end
it 'returns the parent dir' do
expect(subject).to match(/root$/)
end
end
context 'config file in grandparent dir' do
around do |ex|
FileUtils.mkdir_p('root/sub1/sub2')
File.write('root/nanoc.yaml', 'hi')
chdir('root/sub1/sub2') { ex.run }
end
it 'returns the parent dir' do
expect(subject).to match(/root$/)
end
end
context 'no config file in ancestral paths' do
it 'returns nil' do
expect(subject).to be_nil
end
end
end
describe '.enter_site_dir' do
subject do
described_class.enter_site_dir
Dir.getwd
end
context 'config file in current dir' do
before { File.write('nanoc.yaml', 'hi') }
it 'returns the current dir' do
expect(subject).to eq(File.expand_path(Dir.getwd))
end
end
context 'config file in parent dir' do
around do |ex|
FileUtils.mkdir_p('root/sub')
File.write('root/nanoc.yaml', 'hi')
chdir('root/sub') { ex.run }
end
it 'returns the parent dir' do
expect(subject).to match(/root$/)
end
end
context 'config file in grandparent dir' do
around do |ex|
FileUtils.mkdir_p('root/sub1/sub2')
File.write('root/nanoc.yaml', 'hi')
chdir('root/sub1/sub2') { ex.run }
end
it 'enters the parent dir' do
expect(subject).to match(/root$/)
end
end
context 'no config file in ancestral paths' do
it 'raises' do
expect { subject }.to raise_error(::Nanoc::Int::Errors::GenericTrivial, 'The current working directory, nor any of its parents, seems to be a Nanoc site.')
end
end
end
describe '#load_site' do
let(:command_runner) { described_class.new(nil, nil, nil) }
subject { command_runner.load_site }
before { File.write('nanoc.yaml', '{}') }
it 'does not set @site' do
expect(command_runner.instance_variable_get(:@site)).to be_nil
expect { subject }.not_to change { command_runner.instance_variable_get(:@site) }
end
it 'returns site' do
expect(subject).to be_a(Nanoc::Int::Site)
end
end
end
nanoc-4.11.0/nanoc/spec/nanoc/cli/commands/000077500000000000000000000000001340050175000203645ustar00rootroot00000000000000nanoc-4.11.0/nanoc/spec/nanoc/cli/commands/check_spec.rb000066400000000000000000000022521340050175000230010ustar00rootroot00000000000000# frozen_string_literal: true
describe Nanoc::CLI::Commands::Check, site: true, stdio: true do
describe '#run' do
before do
File.write('Checks', "deploy_check :stale\n")
end
context 'without options and arguments' do
subject { Nanoc::CLI.run(['check']) }
context 'no issues for any checks' do
it 'succeeds' do
subject
end
end
context 'issues for deploy check' do
before do
FileUtils.mkdir_p('output')
File.write('output/asdf.txt', 'staaale')
end
it 'fails' do
expect { subject }.to raise_error(Nanoc::Int::Errors::GenericTrivial, 'One or more checks failed')
end
end
context 'issues for non-deploy check' do
before do
FileUtils.mkdir_p('output')
File.write('output/asdf.txt', 'staaale')
File.write('Checks', '')
end
it 'succeeds' do
subject
end
end
end
end
describe 'help' do
subject { Nanoc::CLI.run(%w[help check]) }
it 'shows --deploy as deprecated' do
expect { subject }.to output(/--deploy.*\(deprecated\)/).to_stdout
end
end
end
nanoc-4.11.0/nanoc/spec/nanoc/cli/commands/compile/000077500000000000000000000000001340050175000220145ustar00rootroot00000000000000nanoc-4.11.0/nanoc/spec/nanoc/cli/commands/compile/abstract_spec.rb000066400000000000000000000030251340050175000251560ustar00rootroot00000000000000# frozen_string_literal: true
describe Nanoc::CLI::Commands::CompileListeners::Abstract do
subject { klass.new }
context 'abstract class' do
let(:klass) { described_class }
it 'errors on starting' do
expect { subject.start }.to raise_error(NotImplementedError)
end
it 'stops silently' do
subject.stop
end
end
context 'concrete subclass' do
let(:klass) do
Class.new(described_class) do
attr_reader :started
attr_reader :stopped
def initialize
@started = false
@stopped = false
end
def start
@started = true
end
def stop
@stopped = true
end
end
end
it 'starts' do
subject.start
expect(subject.started).to be
end
it 'stops' do
subject.start
subject.stop
expect(subject.stopped).to be
end
it 'starts safely' do
subject.start_safely
expect(subject.started).to be
end
it 'stops safely' do
subject.start_safely
subject.stop_safely
expect(subject.stopped).to be
end
end
context 'listener that does not start or stop properly' do
let(:klass) do
Class.new(described_class) do
def start
raise 'boom'
end
def stop
raise 'boom'
end
end
end
it 'raises on start, but not stop' do
expect { subject.start_safely }.to raise_error(RuntimeError)
expect { subject.stop_safely }.not_to raise_error
end
end
end
nanoc-4.11.0/nanoc/spec/nanoc/cli/commands/compile/diff_generator_spec.rb000066400000000000000000000021661340050175000263360ustar00rootroot00000000000000# frozen_string_literal: true
describe Nanoc::CLI::Commands::CompileListeners::DiffGenerator do
describe '.enable_for?' do
subject { described_class.enable_for?(command_runner, site) }
let(:options) { {} }
let(:config_hash) { {} }
let(:arguments) { double(:arguments) }
let(:command) { double(:command) }
let(:site) do
Nanoc::Int::Site.new(
config: config,
code_snippets: code_snippets,
data_source: Nanoc::Int::InMemDataSource.new(items, layouts),
)
end
let(:config) { Nanoc::Int::Configuration.new(dir: Dir.getwd, hash: config_hash).with_defaults }
let(:items) { [] }
let(:layouts) { [] }
let(:code_snippets) { [] }
let(:command_runner) do
Nanoc::CLI::Commands::Compile.new(options, arguments, command)
end
context 'default' do
it { is_expected.not_to be }
end
context 'enabled in config' do
let(:config_hash) { { enable_output_diff: true } }
it { is_expected.to be }
end
context 'enabled on command line' do
let(:options) { { diff: true } }
it { is_expected.to be }
end
end
end
nanoc-4.11.0/nanoc/spec/nanoc/cli/commands/compile/file_action_printer_spec.rb000066400000000000000000000110101340050175000273630ustar00rootroot00000000000000# frozen_string_literal: true
describe Nanoc::CLI::Commands::CompileListeners::FileActionPrinter, stdio: true do
let(:listener) { described_class.new(reps: reps) }
before { Timecop.freeze(Time.local(2008, 1, 2, 14, 5, 0)) }
after { Timecop.return }
let(:reps) do
Nanoc::Int::ItemRepRepo.new.tap do |reps|
reps << rep
end
end
let(:item) { Nanoc::Int::Item.new('<%= 1 + 2 %>', {}, '/hi.md') }
let(:rep) do
Nanoc::Int::ItemRep.new(item, :default).tap do |rep|
rep.raw_paths = { default: ['/hi.html'] }
end
end
it 'records from compilation_started to rep_write_ended' do
listener.start
Timecop.freeze(Time.local(2008, 9, 1, 10, 5, 0))
Nanoc::Int::NotificationCenter.post(:compilation_started, rep)
Timecop.freeze(Time.local(2008, 9, 1, 10, 5, 1))
expect { Nanoc::Int::NotificationCenter.post(:rep_write_ended, rep, false, '/foo.html', true, true) }
.to output(/create.*\[1\.00s\]/).to_stdout
end
it 'stops listening after #stop' do
listener.start
listener.stop
Nanoc::Int::NotificationCenter.post(:compilation_started, rep)
expect { Nanoc::Int::NotificationCenter.post(:rep_write_ended, rep, false, '/foo.html', true, true) }
.not_to output(/create/).to_stdout
end
it 'records from compilation_started over compilation_suspended to rep_write_ended' do
listener.start
Timecop.freeze(Time.local(2008, 9, 1, 10, 5, 0))
Nanoc::Int::NotificationCenter.post(:compilation_started, rep)
Timecop.freeze(Time.local(2008, 9, 1, 10, 5, 1))
Nanoc::Int::NotificationCenter.post(:compilation_suspended, rep, :__irrelevant__)
Timecop.freeze(Time.local(2008, 9, 1, 10, 5, 3))
Nanoc::Int::NotificationCenter.post(:compilation_started, rep)
Timecop.freeze(Time.local(2008, 9, 1, 10, 5, 6))
expect { Nanoc::Int::NotificationCenter.post(:rep_write_ended, rep, false, '/foo.html', true, true) }
.to output(/create.*\[4\.00s\]/).to_stdout
end
it 'records from compilation_started over rep_write_{enqueued,started} to rep_write_ended' do
listener.start
Timecop.freeze(Time.local(2008, 9, 1, 10, 5, 0))
Nanoc::Int::NotificationCenter.post(:compilation_started, rep)
Timecop.freeze(Time.local(2008, 9, 1, 10, 5, 1))
Nanoc::Int::NotificationCenter.post(:rep_write_enqueued, rep)
Timecop.freeze(Time.local(2008, 9, 1, 10, 5, 3))
Nanoc::Int::NotificationCenter.post(:rep_write_started, rep)
Timecop.freeze(Time.local(2008, 9, 1, 10, 5, 6))
expect { Nanoc::Int::NotificationCenter.post(:rep_write_ended, rep, false, '/foo.html', true, true) }
.to output(/create.*\[4\.00s\]/).to_stdout
end
context 'log level = high' do
before { listener.start }
before { Nanoc::CLI::Logger.instance.level = :high }
it 'does not print skipped (uncompiled) reps' do
expect { listener.stop }
.not_to output(/skip/).to_stdout
end
it 'prints nothing' do
Nanoc::Int::NotificationCenter.post(:compilation_started, rep)
Timecop.freeze(Time.local(2008, 9, 1, 10, 5, 1))
expect { Nanoc::Int::NotificationCenter.post(:rep_write_ended, rep, false, '/foo.html', false, false) }
.not_to output(/identical/).to_stdout
end
it 'prints nothing' do
Nanoc::Int::NotificationCenter.post(:compilation_started, rep)
Nanoc::Int::NotificationCenter.post(:cached_content_used, rep)
Timecop.freeze(Time.local(2008, 9, 1, 10, 5, 1))
expect { Nanoc::Int::NotificationCenter.post(:rep_write_ended, rep, false, '/foo.html', false, false) }
.not_to output(/cached/).to_stdout
end
end
context 'log level = low' do
before { listener.start }
before { Nanoc::CLI::Logger.instance.level = :low }
it 'prints skipped (uncompiled) reps' do
expect { listener.stop }
.to output(/skip.*\/hi\.html/).to_stdout
end
it 'prints “identical” if not cached' do
Nanoc::Int::NotificationCenter.post(:compilation_started, rep)
Timecop.freeze(Time.local(2008, 9, 1, 10, 5, 1))
expect { Nanoc::Int::NotificationCenter.post(:rep_write_ended, rep, false, '/foo.html', false, false) }
.to output(/identical/).to_stdout
end
it 'prints “cached” if cached' do
Nanoc::Int::NotificationCenter.post(:compilation_started, rep)
Nanoc::Int::NotificationCenter.post(:cached_content_used, rep)
Timecop.freeze(Time.local(2008, 9, 1, 10, 5, 1))
expect { Nanoc::Int::NotificationCenter.post(:rep_write_ended, rep, false, '/foo.html', false, false) }
.to output(/cached/).to_stdout
end
end
end
nanoc-4.11.0/nanoc/spec/nanoc/cli/commands/compile/timing_recorder_spec.rb000066400000000000000000000307241340050175000265350ustar00rootroot00000000000000# frozen_string_literal: true
describe Nanoc::CLI::Commands::CompileListeners::TimingRecorder, stdio: true do
let(:listener) { described_class.new(reps: reps) }
before { Timecop.freeze(Time.local(2008, 1, 2, 14, 5, 0)) }
after { Timecop.return }
before { Nanoc::CLI.verbosity = 2 }
before { listener.start }
after { listener.stop_safely }
let(:reps) do
Nanoc::Int::ItemRepRepo.new.tap do |reps|
reps << rep
end
end
let(:item) { Nanoc::Int::Item.new('<%= 1 + 2 %>', {}, '/hi.md') }
let(:rep) do
Nanoc::Int::ItemRep.new(item, :default).tap do |rep|
rep.raw_paths = { default: ['/hi.html'] }
end
end
let(:other_rep) do
Nanoc::Int::ItemRep.new(item, :other).tap do |rep|
rep.raw_paths = { default: ['/bye.html'] }
end
end
it 'prints filters table' do
Timecop.freeze(Time.local(2008, 9, 1, 10, 5, 0))
Nanoc::Int::NotificationCenter.post(:filtering_started, rep, :erb)
Timecop.freeze(Time.local(2008, 9, 1, 10, 5, 1))
Nanoc::Int::NotificationCenter.post(:filtering_ended, rep, :erb)
Timecop.freeze(Time.local(2008, 9, 1, 10, 14, 1))
Nanoc::Int::NotificationCenter.post(:filtering_started, rep, :erb)
Timecop.freeze(Time.local(2008, 9, 1, 10, 14, 3))
Nanoc::Int::NotificationCenter.post(:filtering_ended, rep, :erb)
expect { listener.stop }
.to output(/^\s*erb │ 2 1\.00s 1\.50s 1\.90s 1\.95s 2\.00s 3\.00s$/).to_stdout
end
it 'records single from filtering_started to filtering_ended' do
Timecop.freeze(Time.local(2008, 9, 1, 10, 5, 0))
Nanoc::Int::NotificationCenter.post(:filtering_started, rep, :erb)
Timecop.freeze(Time.local(2008, 9, 1, 10, 5, 1))
Nanoc::Int::NotificationCenter.post(:filtering_ended, rep, :erb)
expect(listener.filters_summary.get(name: 'erb').min).to eq(1.00)
expect(listener.filters_summary.get(name: 'erb').avg).to eq(1.00)
expect(listener.filters_summary.get(name: 'erb').max).to eq(1.00)
expect(listener.filters_summary.get(name: 'erb').sum).to eq(1.00)
expect(listener.filters_summary.get(name: 'erb').count).to eq(1.00)
end
it 'records multiple from filtering_started to filtering_ended' do
Timecop.freeze(Time.local(2008, 9, 1, 10, 5, 0))
Nanoc::Int::NotificationCenter.post(:filtering_started, rep, :erb)
Timecop.freeze(Time.local(2008, 9, 1, 10, 5, 1))
Nanoc::Int::NotificationCenter.post(:filtering_ended, rep, :erb)
Timecop.freeze(Time.local(2008, 9, 1, 10, 14, 1))
Nanoc::Int::NotificationCenter.post(:filtering_started, rep, :erb)
Timecop.freeze(Time.local(2008, 9, 1, 10, 14, 3))
Nanoc::Int::NotificationCenter.post(:filtering_ended, rep, :erb)
expect(listener.filters_summary.get(name: 'erb').min).to eq(1.00)
expect(listener.filters_summary.get(name: 'erb').avg).to eq(1.50)
expect(listener.filters_summary.get(name: 'erb').max).to eq(2.00)
expect(listener.filters_summary.get(name: 'erb').sum).to eq(3.00)
expect(listener.filters_summary.get(name: 'erb').count).to eq(2.00)
end
it 'records filters in nested filtering_started/filtering_ended' do
Timecop.freeze(Time.local(2008, 9, 1, 10, 5, 0))
Nanoc::Int::NotificationCenter.post(:filtering_started, rep, :outer)
Timecop.freeze(Time.local(2008, 9, 1, 10, 5, 1))
Nanoc::Int::NotificationCenter.post(:filtering_started, rep, :inner)
Timecop.freeze(Time.local(2008, 9, 1, 10, 5, 3))
Nanoc::Int::NotificationCenter.post(:filtering_ended, rep, :inner)
Timecop.freeze(Time.local(2008, 9, 1, 10, 5, 6))
Nanoc::Int::NotificationCenter.post(:filtering_ended, rep, :outer)
expect(listener.filters_summary.get(name: 'inner').min).to eq(2.00)
expect(listener.filters_summary.get(name: 'inner').avg).to eq(2.00)
expect(listener.filters_summary.get(name: 'inner').max).to eq(2.00)
expect(listener.filters_summary.get(name: 'inner').sum).to eq(2.00)
expect(listener.filters_summary.get(name: 'inner').count).to eq(1.00)
expect(listener.filters_summary.get(name: 'outer').min).to eq(6.00)
expect(listener.filters_summary.get(name: 'outer').avg).to eq(6.00)
expect(listener.filters_summary.get(name: 'outer').max).to eq(6.00)
expect(listener.filters_summary.get(name: 'outer').sum).to eq(6.00)
expect(listener.filters_summary.get(name: 'outer').count).to eq(1.00)
end
it 'pauses outer stopwatch when suspended' do
Timecop.freeze(Time.local(2008, 9, 1, 10, 5, 0))
Nanoc::Int::NotificationCenter.post(:compilation_started, rep)
Nanoc::Int::NotificationCenter.post(:filtering_started, rep, :outer)
Timecop.freeze(Time.local(2008, 9, 1, 10, 5, 1))
Nanoc::Int::NotificationCenter.post(:filtering_started, rep, :inner)
Timecop.freeze(Time.local(2008, 9, 1, 10, 5, 3))
Nanoc::Int::NotificationCenter.post(:compilation_suspended, rep, :__anything__)
Timecop.freeze(Time.local(2008, 9, 1, 10, 5, 6))
Nanoc::Int::NotificationCenter.post(:compilation_started, rep)
Timecop.freeze(Time.local(2008, 9, 1, 10, 5, 10))
Nanoc::Int::NotificationCenter.post(:filtering_ended, rep, :inner)
Nanoc::Int::NotificationCenter.post(:filtering_ended, rep, :outer)
expect(listener.filters_summary.get(name: 'outer').min).to eq(7.00)
expect(listener.filters_summary.get(name: 'outer').avg).to eq(7.00)
expect(listener.filters_summary.get(name: 'outer').max).to eq(7.00)
expect(listener.filters_summary.get(name: 'outer').sum).to eq(7.00)
expect(listener.filters_summary.get(name: 'outer').count).to eq(1.00)
end
it 'records single from filtering_started over compilation_{suspended,started} to filtering_ended' do
Nanoc::Int::NotificationCenter.post(:compilation_started, rep)
Timecop.freeze(Time.local(2008, 9, 1, 10, 5, 0))
Nanoc::Int::NotificationCenter.post(:filtering_started, rep, :erb)
Timecop.freeze(Time.local(2008, 9, 1, 10, 5, 1))
Nanoc::Int::NotificationCenter.post(:compilation_suspended, rep, :__anything__)
Timecop.freeze(Time.local(2008, 9, 1, 10, 5, 3))
Nanoc::Int::NotificationCenter.post(:compilation_started, rep)
Timecop.freeze(Time.local(2008, 9, 1, 10, 5, 7))
Nanoc::Int::NotificationCenter.post(:filtering_ended, rep, :erb)
expect(listener.filters_summary.get(name: 'erb').min).to eq(5.00)
expect(listener.filters_summary.get(name: 'erb').avg).to eq(5.00)
expect(listener.filters_summary.get(name: 'erb').max).to eq(5.00)
expect(listener.filters_summary.get(name: 'erb').sum).to eq(5.00)
expect(listener.filters_summary.get(name: 'erb').count).to eq(1.00)
end
it 'records single phase start+stop' do
Timecop.freeze(Time.local(2008, 9, 1, 10, 5, 0))
Nanoc::Int::NotificationCenter.post(:phase_started, 'donkey', rep)
Timecop.freeze(Time.local(2008, 9, 1, 10, 5, 1))
Nanoc::Int::NotificationCenter.post(:phase_ended, 'donkey', rep)
expect(listener.phases_summary.get(name: 'donkey').min).to eq(1.00)
expect(listener.phases_summary.get(name: 'donkey').avg).to eq(1.00)
expect(listener.phases_summary.get(name: 'donkey').max).to eq(1.00)
expect(listener.phases_summary.get(name: 'donkey').sum).to eq(1.00)
expect(listener.phases_summary.get(name: 'donkey').count).to eq(1.00)
end
it 'records multiple phase start+stop' do
Timecop.freeze(Time.local(2008, 9, 1, 10, 5, 0))
Nanoc::Int::NotificationCenter.post(:phase_started, 'donkey', rep)
Timecop.freeze(Time.local(2008, 9, 1, 10, 5, 1))
Nanoc::Int::NotificationCenter.post(:phase_ended, 'donkey', rep)
Timecop.freeze(Time.local(2008, 9, 1, 11, 6, 0))
Nanoc::Int::NotificationCenter.post(:phase_started, 'donkey', rep)
Timecop.freeze(Time.local(2008, 9, 1, 11, 6, 2))
Nanoc::Int::NotificationCenter.post(:phase_ended, 'donkey', rep)
expect(listener.phases_summary.get(name: 'donkey').min).to eq(1.00)
expect(listener.phases_summary.get(name: 'donkey').avg).to eq(1.50)
expect(listener.phases_summary.get(name: 'donkey').max).to eq(2.00)
expect(listener.phases_summary.get(name: 'donkey').sum).to eq(3.00)
expect(listener.phases_summary.get(name: 'donkey').count).to eq(2.00)
end
it 'records single phase start+yield+resume+stop' do
Timecop.freeze(Time.local(2008, 9, 1, 10, 5, 0))
Nanoc::Int::NotificationCenter.post(:phase_started, 'donkey', rep)
Timecop.freeze(Time.local(2008, 9, 1, 10, 5, 1))
Nanoc::Int::NotificationCenter.post(:phase_yielded, 'donkey', rep)
Timecop.freeze(Time.local(2008, 9, 1, 11, 6, 0))
Nanoc::Int::NotificationCenter.post(:phase_resumed, 'donkey', rep)
Timecop.freeze(Time.local(2008, 9, 1, 11, 6, 2))
Nanoc::Int::NotificationCenter.post(:phase_ended, 'donkey', rep)
expect(listener.phases_summary.get(name: 'donkey').min).to eq(3.00)
expect(listener.phases_summary.get(name: 'donkey').avg).to eq(3.00)
expect(listener.phases_summary.get(name: 'donkey').max).to eq(3.00)
expect(listener.phases_summary.get(name: 'donkey').sum).to eq(3.00)
expect(listener.phases_summary.get(name: 'donkey').count).to eq(1.00)
end
it 'records single phase start+yield+abort+start+stop' do
Timecop.freeze(Time.local(2008, 9, 1, 10, 5, 0))
Nanoc::Int::NotificationCenter.post(:phase_started, 'donkey', rep)
Timecop.freeze(Time.local(2008, 9, 1, 10, 5, 1))
Nanoc::Int::NotificationCenter.post(:phase_yielded, 'donkey', rep)
Timecop.freeze(Time.local(2008, 9, 1, 11, 6, 0))
Nanoc::Int::NotificationCenter.post(:phase_aborted, 'donkey', rep)
Timecop.freeze(Time.local(2008, 9, 1, 12, 7, 2))
Nanoc::Int::NotificationCenter.post(:phase_started, 'donkey', rep)
Timecop.freeze(Time.local(2008, 9, 1, 12, 7, 5))
Nanoc::Int::NotificationCenter.post(:phase_ended, 'donkey', rep)
expect(listener.phases_summary.get(name: 'donkey').min).to eq(1.00)
expect(listener.phases_summary.get(name: 'donkey').avg).to eq(2.00)
expect(listener.phases_summary.get(name: 'donkey').max).to eq(3.00)
expect(listener.phases_summary.get(name: 'donkey').sum).to eq(4.00)
expect(listener.phases_summary.get(name: 'donkey').count).to eq(2.00)
end
it 'records stage duration' do
Nanoc::Int::NotificationCenter.post(:stage_ran, 1.23, 'donkey_stage')
expect(listener.stages_summary.get(name: 'donkey_stage').sum).to eq(1.23)
expect(listener.stages_summary.get(name: 'donkey_stage').count).to eq(1)
end
it 'prints stage durations' do
Nanoc::Int::NotificationCenter.post(:stage_ran, 1.23, 'donkey_stage')
expect { listener.stop }
.to output(/^\s*donkey_stage │ 1\.23s$/).to_stdout
end
it 'prints out outdatedness rule durations' do
Nanoc::Int::NotificationCenter.post(:outdatedness_rule_ran, 1.0, Nanoc::Int::OutdatednessRules::CodeSnippetsModified)
expect { listener.stop }
.to output(/^\s*CodeSnippetsModified │ 1 1\.00s 1\.00s 1\.00s 1\.00s 1\.00s 1\.00s$/).to_stdout
end
it 'records single outdatedness rule duration' do
Nanoc::Int::NotificationCenter.post(:outdatedness_rule_ran, 1.0, Nanoc::Int::OutdatednessRules::CodeSnippetsModified)
expect(listener.outdatedness_rules_summary.get(name: 'CodeSnippetsModified').min).to eq(1.00)
expect(listener.outdatedness_rules_summary.get(name: 'CodeSnippetsModified').avg).to eq(1.00)
expect(listener.outdatedness_rules_summary.get(name: 'CodeSnippetsModified').max).to eq(1.00)
expect(listener.outdatedness_rules_summary.get(name: 'CodeSnippetsModified').sum).to eq(1.00)
expect(listener.outdatedness_rules_summary.get(name: 'CodeSnippetsModified').count).to eq(1.00)
end
it 'records multiple outdatedness rule duration' do
Nanoc::Int::NotificationCenter.post(:outdatedness_rule_ran, 1.0, Nanoc::Int::OutdatednessRules::CodeSnippetsModified)
Nanoc::Int::NotificationCenter.post(:outdatedness_rule_ran, 3.0, Nanoc::Int::OutdatednessRules::CodeSnippetsModified)
expect(listener.outdatedness_rules_summary.get(name: 'CodeSnippetsModified').min).to eq(1.00)
expect(listener.outdatedness_rules_summary.get(name: 'CodeSnippetsModified').avg).to eq(2.00)
expect(listener.outdatedness_rules_summary.get(name: 'CodeSnippetsModified').max).to eq(3.00)
expect(listener.outdatedness_rules_summary.get(name: 'CodeSnippetsModified').sum).to eq(4.00)
expect(listener.outdatedness_rules_summary.get(name: 'CodeSnippetsModified').count).to eq(2.00)
end
it 'prints load store durations' do
Nanoc::Int::NotificationCenter.post(:store_loaded, 1.23, Nanoc::Int::ChecksumStore)
expect { listener.stop }
.to output(/^\s*Nanoc::Int::ChecksumStore │ 1\.23s$/).to_stdout
end
it 'skips printing empty metrics' do
expect { listener.stop }
.not_to output(/filters|phases|stages/).to_stdout
end
end
nanoc-4.11.0/nanoc/spec/nanoc/cli/commands/compile_spec.rb000066400000000000000000000045451340050175000233630ustar00rootroot00000000000000# frozen_string_literal: true
describe Nanoc::CLI::Commands::Compile, site: true, stdio: true do
describe '#run' do
it 'starts and stops listeners as needed' do
test_listener_class = Class.new(::Nanoc::CLI::Commands::CompileListeners::Abstract) do
def start
@started = true
end
def stop
@stopped = true
end
def started?
@started
end
def stopped?
@stopped
end
end
expect(Nanoc::CLI::Commands::CompileListeners::Aggregate)
.to receive(:default_listener_classes)
.and_return([test_listener_class])
listener = test_listener_class.new
expect(test_listener_class)
.to receive(:new)
.and_return(listener)
options = {}
arguments = []
cmd = nil
cmd_runner = Nanoc::CLI::Commands::Compile.new(options, arguments, cmd)
cmd_runner.run
expect(listener).to be_started
expect(listener).to be_stopped
end
describe '--watch', fork: true do
it 'watches with --watch' do
pipe_stdout_read, pipe_stdout_write = IO.pipe
pid = fork do
trap(:INT) { exit(0) }
pipe_stdout_read.close
$stdout = pipe_stdout_write
# TODO: Use Nanoc::CLI.run instead (when --watch is no longer experimental)
options = { watch: true }
arguments = []
cmd = nil
cmd_runner = Nanoc::CLI::Commands::Compile.new(options, arguments, cmd)
cmd_runner.run
end
pipe_stdout_write.close
# Wait until ready
Timeout.timeout(5) do
progress = 0
pipe_stdout_read.each_line do |line|
progress += 1 if line.start_with?('Listening for lib/ changes')
progress += 1 if line.start_with?('Listening for site changes')
break if progress == 2
end
end
sleep 0.5 # Still needs time to warm up…
File.write('content/lol.html', 'hej')
sleep_until { File.file?('output/lol.html') }
expect(File.read('output/lol.html')).to eq('hej')
sleep 1.0 # HFS+ mtime resolution is 1s
File.write('content/lol.html', 'bye')
sleep_until { File.read('output/lol.html') == 'bye' }
# Stop
Process.kill('INT', pid)
Process.waitpid(pid)
end
end
end
end
nanoc-4.11.0/nanoc/spec/nanoc/cli/commands/deploy_spec.rb000066400000000000000000000217531340050175000232270ustar00rootroot00000000000000# frozen_string_literal: true
describe Nanoc::CLI::Commands::Deploy, site: true, stdio: true do
before do
skip_unless_have_command 'rsync'
end
describe '#run' do
let(:config) { {} }
before do
# Prevent double-loading
expect(Nanoc::CLI).to receive(:setup)
File.write('nanoc.yaml', YAML.dump(config))
end
shared_examples 'no effective deploy' do
it 'does not write any files' do
expect { run rescue nil }.not_to change { Dir['remote/*'] }
expect(Dir['remote/*']).to be_empty
end
end
shared_examples 'effective deploy' do
it 'writes files' do
expect { run }.to change { Dir['remote/*'] }.from([]).to(['remote/success.txt'])
expect(File.read('remote/success.txt')).to eql('hurrah')
end
end
shared_examples 'attempted/effective deploy' do
context 'no checks' do
include_examples 'effective deploy'
end
context 'checks fail' do
before do
File.write(
'Checks',
"check :donkey do\n" \
" add_issue('things are broken', subject: 'success.txt')\n" \
"end\n" \
"\n" \
"deploy_check :donkey\n",
)
end
include_examples 'no effective deploy'
context 'checks disabled' do
context '--no-check' do
let(:command) { super() + ['--no-check'] }
include_examples 'effective deploy'
end
context '--Ck' do
let(:command) { super() + ['-C'] }
include_examples 'effective deploy'
end
end
end
context 'checks pass' do
before do
File.write(
'Checks',
"check :donkey do\n" \
"end\n" \
"\n" \
"deploy_check :donkey\n",
)
end
include_examples 'effective deploy'
end
end
describe 'listing deployers' do
shared_examples 'lists all deployers' do
let(:run) { Nanoc::CLI.run(command) }
it 'lists all deployers' do
expect { run }.to output(/Available deployers:\n fog\n git\n rsync/).to_stdout
end
include_examples 'no effective deploy'
end
context '--list-deployers' do
let(:command) { %w[deploy --list-deployers] }
include_examples 'lists all deployers'
end
context '-D' do
let(:command) { %w[deploy -D] }
include_examples 'lists all deployers'
end
end
describe 'listing deployment configurations' do
shared_examples 'lists all deployment configurations' do
let(:run) { Nanoc::CLI.run(command) }
context 'no deployment configurations' do
let(:config) { { donkeys: 'lots' } }
it 'says nothing is found' do
expect { run }.to output(/No deployment configurations./).to_stdout
end
include_examples 'no effective deploy'
end
context 'some deployment configurations' do
let(:config) do
{
deploy: {
production: {
kind: 'rsync',
dst: 'remote',
},
staging: {
kind: 'rsync',
dst: 'remote',
},
},
}
end
it 'says some targets are found' do
expect { run }.to output(/Available deployment configurations:\n production\n staging/).to_stdout
end
include_examples 'no effective deploy'
end
end
context '--list' do
let(:command) { %w[deploy --list] }
include_examples 'lists all deployment configurations'
end
context '-L' do
let(:command) { %w[deploy -L] }
include_examples 'lists all deployment configurations'
end
end
describe 'deploying' do
let(:run) { Nanoc::CLI.run(command) }
let(:command) { %w[deploy] }
before do
FileUtils.mkdir_p('output')
FileUtils.mkdir_p('remote')
File.write('output/success.txt', 'hurrah')
end
shared_examples 'missing kind warning' do
it 'warns about missing kind' do
expect { run }.to output(/Warning: The specified deploy target does not have a kind attribute. Assuming rsync./).to_stderr
end
end
context 'no deploy configs' do
it 'errors' do
expect { run }.to raise_error(
Nanoc::Int::Errors::GenericTrivial,
'The site has no deployment configurations.',
)
end
include_examples 'no effective deploy'
context 'configuration created in preprocessor' do
before do
File.write(
'Rules',
"preprocess do\n" \
" @config[:deploy] = {\n" \
" default: { dst: 'remote' },\n" \
" }\n" \
"end\n\n" + File.read('Rules'),
)
end
include_examples 'attempted/effective deploy'
end
end
context 'some deploy configs' do
let(:config) do
{
deploy: {
irrelevant: {
kind: 'rsync',
dst: 'remote',
},
},
}
end
context 'default target' do
context 'requested deploy config does not exist' do
it 'errors' do
expect { run }.to raise_error(
Nanoc::Int::Errors::GenericTrivial,
'The site has no deployment configuration named `default`.',
)
end
include_examples 'no effective deploy'
end
context 'requested deploy config exists' do
let(:config) do
{
deploy: {
default: {
kind: 'rsync',
dst: 'remote',
},
},
}
end
include_examples 'attempted/effective deploy'
context 'dry run' do
let(:command) { super() + ['--dry-run'] }
include_examples 'no effective deploy'
end
end
context 'requested deploy config exists, but has no kind' do
let(:config) do
{
deploy: {
default: {
dst: 'remote',
},
},
}
end
include_examples 'attempted/effective deploy'
include_examples 'missing kind warning'
context 'dry run' do
let(:command) { super() + ['--dry-run'] }
include_examples 'no effective deploy'
end
end
end
shared_examples 'deploy with non-default target' do
context 'requested deploy config does not exist' do
it 'errors' do
expect { run }.to raise_error(
Nanoc::Int::Errors::GenericTrivial,
'The site has no deployment configuration named `production`.',
)
end
include_examples 'no effective deploy'
end
context 'requested deploy config exists' do
let(:config) do
{
deploy: {
production: {
kind: 'rsync',
dst: 'remote',
},
},
}
end
include_examples 'attempted/effective deploy'
context 'dry run' do
let(:command) { (super() + ['--dry-run']) }
include_examples 'no effective deploy'
end
end
context 'requested deploy config exists, but has no kind' do
let(:config) do
{
deploy: {
production: {
dst: 'remote',
},
},
}
end
include_examples 'attempted/effective deploy'
include_examples 'missing kind warning'
context 'dry run' do
let(:command) { (super() + ['--dry-run']) }
include_examples 'no effective deploy'
end
end
end
context 'non-default target, specified as argument' do
let(:command) { %w[deploy production] }
include_examples 'deploy with non-default target'
end
context 'non-default target, specified as option (--target)' do
let(:command) { %w[deploy --target production] }
include_examples 'deploy with non-default target'
end
context 'multiple targets specified' do
let(:command) { %w[deploy --target staging production] }
it 'errors' do
expect { run }.to raise_error(
Nanoc::Int::Errors::GenericTrivial,
'Only one deployment target can be specified on the command line.',
)
end
end
end
end
end
end
nanoc-4.11.0/nanoc/spec/nanoc/cli/commands/shell_spec.rb000066400000000000000000000052561340050175000230420ustar00rootroot00000000000000# frozen_string_literal: true
describe Nanoc::CLI::Commands::Shell, site: true, stdio: true do
describe '#run' do
before do
# Prevent double-loading
expect(Nanoc::CLI).to receive(:setup)
File.write('content/hello.md', 'Hello!')
File.write('Rules', <<~EOS)
preprocess do
@items['/hello.*'].raw_content = 'Better hello!'
end
compile '/**/*' do
end
EOS
end
it 'can be invoked' do
expect_any_instance_of(Nanoc::Int::Context).to receive(:pry) do |ctx|
expect(ctx.items.size).to eq(1)
expect(ctx.items.to_a[0]._unwrap.content.string).to eq('Hello!')
end
Nanoc::CLI.run(['shell'])
end
it 'can be invoked as sh' do
expect_any_instance_of(Nanoc::Int::Context).to receive(:pry) do |ctx|
expect(ctx.items.size).to eq(1)
expect(ctx.items.to_a[0]._unwrap.content.string).to eq('Hello!')
end
Nanoc::CLI.run(['sh'])
end
it 'can be invoked as console' do
expect_any_instance_of(Nanoc::Int::Context).to receive(:pry) do |ctx|
expect(ctx.items.size).to eq(1)
expect(ctx.items.to_a[0]._unwrap.content.string).to eq('Hello!')
end
Nanoc::CLI.run(['console'])
end
it 'will preprocess if requested' do
expect_any_instance_of(Nanoc::Int::Context).to receive(:pry) do |ctx|
expect(ctx.items.size).to eq(1)
expect(ctx.items.to_a[0]._unwrap.content.string).to eq('Better hello!')
end
Nanoc::CLI.run(['shell', '--preprocess'])
end
end
describe '#env_for_site' do
subject { described_class.env_for_site(site) }
before do
File.write('content/hello.md', 'Hello!')
File.write('layouts/default.erb', 'MY SITE! <%= yield %>')
end
let(:site) do
Nanoc::Int::SiteLoader.new.new_from_cwd
end
it 'returns views' do
expect(subject[:items]).to be_a(Nanoc::ItemCollectionWithRepsView)
expect(subject[:layouts]).to be_a(Nanoc::LayoutCollectionView)
expect(subject[:config]).to be_a(Nanoc::ConfigView)
end
it 'returns correct items' do
expect(subject[:items].size).to eq(1)
expect(subject[:items].first.identifier.to_s).to eq('/hello.md')
end
it 'returns correct layouts' do
expect(subject[:layouts].size).to eq(1)
expect(subject[:layouts].first.identifier.to_s).to eq('/default.erb')
end
it 'returns items with reps' do
expect(subject[:items].first.reps).not_to be_nil
expect(subject[:items].first.reps.first.name).to eq(:default)
end
it 'returns items with rep paths' do
expect(subject[:items].first.reps.first.path).to eq('/hello.md')
end
end
end
nanoc-4.11.0/nanoc/spec/nanoc/cli/commands/show_data_spec.rb000066400000000000000000000246461340050175000237100ustar00rootroot00000000000000# frozen_string_literal: true
describe Nanoc::CLI::Commands::ShowData, stdio: true do
describe '#print_item_dependencies' do
subject { runner.send(:print_item_dependencies, items, dependency_store) }
let(:runner) do
described_class.new(options, arguments, command)
end
let(:options) { {} }
let(:arguments) { [] }
let(:command) { double(:command) }
let(:items) do
Nanoc::Int::ItemCollection.new(
config,
[
item_about,
item_dog,
item_other,
],
)
end
let(:item_about) { Nanoc::Int::Item.new('About Me', {}, '/about.md') }
let(:item_dog) { Nanoc::Int::Item.new('About My Dog', {}, '/dog.md') }
let(:item_other) { Nanoc::Int::Item.new('Raw Data', {}, '/other.dat') }
let(:config) { Nanoc::Int::Configuration.new(dir: Dir.getwd).with_defaults }
let(:dependency_store) do
Nanoc::Int::DependencyStore.new(items, layouts, config)
end
let(:layouts) do
Nanoc::Int::LayoutCollection.new(config)
end
it 'prints a legend' do
expect { subject }.to output(%r{Item dependencies =+\n\nLegend:}).to_stdout
end
context 'no dependencies' do
it 'outputs no dependencies for /about.md' do
expect { subject }.to output(%r{^item /about.md depends on:\n \(nothing\)$}m).to_stdout
end
it 'outputs no dependencies for /dog.md' do
expect { subject }.to output(%r{^item /dog.md depends on:\n \(nothing\)$}m).to_stdout
end
it 'outputs no dependencies for /other.dat' do
expect { subject }.to output(%r{^item /other.dat depends on:\n \(nothing\)$}m).to_stdout
end
end
context 'dependency (without props) from config to dog' do
before do
dependency_store.record_dependency(item_dog, config)
end
it 'outputs no dependencies for /about.md' do
expect { subject }.to output(%r{^item /about.md depends on:\n \(nothing\)$}m).to_stdout
end
it 'outputs dependencies for /dog.md' do
expect { subject }.to output(%r{^item /dog.md depends on:\n \[ config \] \(racp\) $}m).to_stdout
end
it 'outputs no dependencies for /other.dat' do
expect { subject }.to output(%r{^item /other.dat depends on:\n \(nothing\)$}m).to_stdout
end
end
context 'dependency (without props) from about to dog' do
before do
dependency_store.record_dependency(item_dog, item_about)
end
it 'outputs no dependencies for /about.md' do
expect { subject }.to output(%r{^item /about.md depends on:\n \(nothing\)$}m).to_stdout
end
it 'outputs dependencies for /dog.md' do
expect { subject }.to output(%r{^item /dog.md depends on:\n \[ item \] \(racp\) /about.md$}m).to_stdout
end
it 'outputs no dependencies for /other.dat' do
expect { subject }.to output(%r{^item /other.dat depends on:\n \(nothing\)$}m).to_stdout
end
end
context 'dependency (with raw_content prop) from about to dog' do
before do
dependency_store.record_dependency(item_dog, item_about, raw_content: true)
end
it 'outputs dependencies for /dog.md' do
expect { subject }.to output(%r{^item /dog.md depends on:\n \[ item \] \(r___\) /about.md$}m).to_stdout
end
end
context 'dependency (with attributes prop) from about to dog' do
before do
dependency_store.record_dependency(item_dog, item_about, attributes: true)
end
it 'outputs dependencies for /dog.md' do
expect { subject }.to output(%r{^item /dog.md depends on:\n \[ item \] \(_a__\) /about.md$}m).to_stdout
end
end
context 'dependency (with attributes prop) from config to dog' do
before do
dependency_store.record_dependency(item_dog, config, attributes: true)
end
it 'outputs dependencies for /dog.md' do
expect { subject }.to output(%r{^item /dog.md depends on:\n \[ config \] \(_a__\) $}m).to_stdout
end
end
context 'dependency (with compiled_content prop) from about to dog' do
before do
dependency_store.record_dependency(item_dog, item_about, compiled_content: true)
end
it 'outputs dependencies for /dog.md' do
expect { subject }.to output(%r{^item /dog.md depends on:\n \[ item \] \(__c_\) /about.md$}m).to_stdout
end
end
context 'dependency (with path prop) from about to dog' do
before do
dependency_store.record_dependency(item_dog, item_about, path: true)
end
it 'outputs dependencies for /dog.md' do
expect { subject }.to output(%r{^item /dog.md depends on:\n \[ item \] \(___p\) /about.md$}m).to_stdout
end
end
context 'dependency (with multiple props) from about to dog' do
before do
dependency_store.record_dependency(item_dog, item_about, attributes: true, raw_content: true)
end
it 'outputs dependencies for /dog.md' do
expect { subject }.to output(%r{^item /dog.md depends on:\n \[ item \] \(ra__\) /about.md$}m).to_stdout
end
end
context 'dependency onto all items' do
before do
dependency_store.record_dependency(item_dog, items, raw_content: true)
end
it 'outputs dependencies for /dog.md' do
expect { subject }.to output(%r{^item /dog.md depends on:\n \[ items \] \(r___\) matching any$}m).to_stdout
end
end
context 'dependency onto one specific item' do
before do
dependency_store.record_dependency(item_dog, items, raw_content: ['/about.*'])
end
it 'outputs dependencies for /dog.md' do
expect { subject }.to output(%r{^item /dog.md depends on:\n \[ items \] \(r___\) matching any of /about\.\*$}m).to_stdout
end
end
context 'dependency onto multiple specific items' do
before do
dependency_store.record_dependency(item_dog, items, raw_content: ['/about.*'])
dependency_store.record_dependency(item_dog, items, raw_content: ['/giraffe.*'])
end
it 'outputs dependencies for /dog.md' do
expect { subject }.to output(%r{^item /dog.md depends on:\n \[ items \] \(r___\) matching any of /about\.\*, /giraffe\.\*$}m).to_stdout
end
end
end
describe '#print_item_rep_outdatedness' do
subject { runner.send(:print_item_rep_outdatedness, items, outdatedness_checker, reps) }
let(:runner) do
described_class.new(options, arguments, command)
end
let(:options) { {} }
let(:arguments) { [] }
let(:command) { double(:command) }
let(:config) { Nanoc::Int::Configuration.new(dir: Dir.getwd) }
let(:items) do
Nanoc::Int::ItemCollection.new(
config,
[
item_about,
item_dog,
],
)
end
let(:item_about) { Nanoc::Int::Item.new('About Me', {}, '/about.md') }
let(:item_dog) { Nanoc::Int::Item.new('About My Dog', {}, '/dog.md') }
let(:item_rep_about) { Nanoc::Int::ItemRep.new(item_about, :default) }
let(:item_rep_dog) { Nanoc::Int::ItemRep.new(item_dog, :default) }
let(:site) { double(:site) }
let(:outdatedness_checker) { double(:outdatedness_checker) }
let(:reps) do
{
item_about => [item_rep_about],
item_dog => [item_rep_dog],
}
end
context 'not outdated' do
before do
allow(outdatedness_checker).to receive(:outdatedness_reasons_for).with(item_rep_about).and_return([])
allow(outdatedness_checker).to receive(:outdatedness_reasons_for).with(item_rep_dog).and_return([])
end
example do
expect { subject }.to output(%r{^item /about.md, rep default:\n is not outdated$}).to_stdout
end
example do
expect { subject }.to output(%r{^item /dog.md, rep default:\n is not outdated$}).to_stdout
end
end
context 'outdated' do
before do
reasons_about =
[
Nanoc::Int::OutdatednessReasons::ContentModified,
Nanoc::Int::OutdatednessReasons::AttributesModified.new([:title]),
]
reasons_dog =
[Nanoc::Int::OutdatednessReasons::DependenciesOutdated]
allow(outdatedness_checker).to receive(:outdatedness_reasons_for)
.with(item_rep_about).and_return(reasons_about)
allow(outdatedness_checker).to receive(:outdatedness_reasons_for)
.with(item_rep_dog).and_return(reasons_dog)
end
example do
expect { subject }.to output(%r{^item /about.md, rep default:\n is outdated:\n - The content of this item has been modified since the last time the site was compiled.\n - The attributes of this item have been modified since the last time the site was compiled.$}).to_stdout
end
example do
expect { subject }.to output(%r{^item /dog.md, rep default:\n is outdated:\n - This item uses content or attributes that have changed since the last time the site was compiled.$}).to_stdout
end
end
end
describe '#print_layouts' do
subject { runner.send(:print_layouts, layouts, outdatedness_checker) }
let(:runner) do
described_class.new(options, arguments, command)
end
let(:options) { {} }
let(:arguments) { [] }
let(:command) { double(:command) }
let(:config) { Nanoc::Int::Configuration.new(dir: Dir.getwd) }
let(:layouts) do
Nanoc::Int::LayoutCollection.new(config, [layout])
end
let(:layout) { Nanoc::Int::Layout.new('stuff', {}, '/default.erb') }
let(:site) { double(:site) }
let(:outdatedness_checker) { double(:outdatedness_checker) }
context 'not outdated' do
before do
allow(outdatedness_checker).to receive(:outdatedness_reasons_for).with(layout).and_return([])
end
example do
expect { subject }.to output(%r{^layout /default.erb:\n is not outdated$}).to_stdout
end
end
context 'outdated' do
before do
reasons =
[
Nanoc::Int::OutdatednessReasons::ContentModified,
Nanoc::Int::OutdatednessReasons::AttributesModified.new([:title]),
]
allow(outdatedness_checker).to receive(:outdatedness_reasons_for)
.with(layout).and_return(reasons)
end
example do
expect { subject }.to output(%r{^layout /default.erb:\n is outdated:\n - The content of this item has been modified since the last time the site was compiled.\n - The attributes of this item have been modified since the last time the site was compiled.$}).to_stdout
end
end
end
end
nanoc-4.11.0/nanoc/spec/nanoc/cli/commands/show_plugins_spec.rb000066400000000000000000000010421340050175000244410ustar00rootroot00000000000000# frozen_string_literal: true
describe Nanoc::CLI::Commands::ShowPlugins, site: true, stdio: true do
describe '#run' do
it 'can be invoked' do
Nanoc::CLI.run(['show-plugins'])
end
context 'site with plugins' do
before do
File.write('lib/default.rb', 'Nanoc::Filter.define(:show_plugins_x) {}')
end
it 'outputs show_plugins_x under the right section' do
expect { Nanoc::CLI.run(['show-plugins']) }
.to output(/ custom:\n show_plugins_x/).to_stdout
end
end
end
end
nanoc-4.11.0/nanoc/spec/nanoc/cli/commands/show_rules_spec.rb000066400000000000000000000067721340050175000241310ustar00rootroot00000000000000# frozen_string_literal: true
describe Nanoc::CLI::Commands::ShowRules, stdio: true, site: true do
describe '#run' do
subject { runner.run }
let(:runner) do
described_class.new(options, arguments, command)
end
let(:options) { {} }
let(:arguments) { [] }
let(:command) { double(:command) }
let(:site) do
double(
:site,
items: items,
layouts: layouts,
compiler: compiler,
config: config,
)
end
let(:items) do
Nanoc::Int::ItemCollection.new(
config,
[
Nanoc::Int::Item.new('About Me', {}, '/about.md'),
Nanoc::Int::Item.new('About My Dog', {}, '/dog.md'),
Nanoc::Int::Item.new('Raw Data', {}, '/other.dat'),
],
)
end
let(:reps) do
Nanoc::Int::ItemRepRepo.new.tap do |reps|
reps << Nanoc::Int::ItemRep.new(items['/about.md'], :default)
reps << Nanoc::Int::ItemRep.new(items['/about.md'], :text)
reps << Nanoc::Int::ItemRep.new(items['/dog.md'], :default)
reps << Nanoc::Int::ItemRep.new(items['/dog.md'], :text)
reps << Nanoc::Int::ItemRep.new(items['/other.dat'], :default)
end
end
let(:layouts) do
Nanoc::Int::LayoutCollection.new(
config,
[
Nanoc::Int::Layout.new('Default', {}, '/default.erb'),
Nanoc::Int::Layout.new('Article', {}, '/article.haml'),
Nanoc::Int::Layout.new('Other', {}, '/other.xyzzy'),
],
)
end
let(:config) { Nanoc::Int::Configuration.new(dir: Dir.getwd).with_defaults }
let(:action_provider) { double(:action_provider, rules_collection: rules_collection) }
let(:compiler) { double(:compiler) }
let(:rules_collection) do
Nanoc::RuleDSL::RulesCollection.new.tap do |rc|
rc.add_item_compilation_rule(
Nanoc::RuleDSL::CompilationRule.new(Nanoc::Int::Pattern.from('/dog.*'), :default, proc {}),
)
rc.add_item_compilation_rule(
Nanoc::RuleDSL::CompilationRule.new(Nanoc::Int::Pattern.from('/*.md'), :default, proc {}),
)
rc.add_item_compilation_rule(
Nanoc::RuleDSL::CompilationRule.new(Nanoc::Int::Pattern.from('/**/*'), :text, proc {}),
)
rc.layout_filter_mapping[Nanoc::Int::Pattern.from('/*.haml')] = [:haml, {}]
rc.layout_filter_mapping[Nanoc::Int::Pattern.from('/*.erb')] = [:erb, {}]
end
end
let(:expected_out) do
<<-EOS
\e[1m\e[33mItem /about.md\e[0m:
Rep default: /*.md
Rep text: /**/*
\e[1m\e[33mItem /dog.md\e[0m:
Rep default: /dog.*
Rep text: /**/*
\e[1m\e[33mItem /other.dat\e[0m:
Rep default: (none)
\e[1m\e[33mLayout /article.haml\e[0m:
/*.haml
\e[1m\e[33mLayout /default.erb\e[0m:
/*.erb
\e[1m\e[33mLayout /other.xyzzy\e[0m:
(none)
EOS
.gsub(/^ {8}/, '')
end
it 'writes item and layout rules to stdout' do
expect(runner).to receive(:load_site).and_return(site)
expect(Nanoc::Int::Compiler).to receive(:new_for).with(site).and_return(compiler)
expect(compiler).to receive(:run_until_reps_built).and_return(reps: reps)
expect(Nanoc::RuleDSL::ActionProvider).to receive(:for).with(site).and_return(action_provider)
expect { subject }.to output(expected_out).to_stdout
end
it 'writes status information to stderr' do
expect { subject }.to output("Loading site… done\n").to_stderr
end
end
end
nanoc-4.11.0/nanoc/spec/nanoc/cli/commands/view_spec.rb000066400000000000000000000052431340050175000227010ustar00rootroot00000000000000# frozen_string_literal: true
require 'net/http'
describe Nanoc::CLI::Commands::View, site: true, stdio: true, fork: true do
describe '#run' do
def run_nanoc_cmd(cmd)
pid = fork { Nanoc::CLI.run(cmd) }
# Wait for server to start up
20.times do |i|
begin
Net::HTTP.get('127.0.0.1', '/', 50_385)
break
rescue Errno::ECONNREFUSED, Errno::ECONNRESET
sleep(0.1 * 1.1**i)
next
end
raise 'Server did not start up in time'
end
yield
ensure
Process.kill('TERM', pid)
end
context 'default configuration' do
it 'serves /index.html as /' do
File.write('output/index.html', 'Hello there! Nanoc loves you! <3')
run_nanoc_cmd(['view', '--port', '50385']) do
expect(Net::HTTP.get('127.0.0.1', '/', 50_385)).to eql('Hello there! Nanoc loves you! <3')
end
end
it 'does not serve /index.xhtml as /' do
File.write('output/index.xhtml', 'Hello there! Nanoc loves you! <3')
run_nanoc_cmd(['view', '--port', '50385']) do
expect(Net::HTTP.get('127.0.0.1', '/', 50_385)).to eql("File not found: /\n")
end
end
end
context 'index_filenames including index.xhtml' do
before do
File.write('nanoc.yaml', 'index_filenames: [index.xhtml]')
end
it 'serves /index.xhtml as /' do
File.write('output/index.xhtml', 'Hello there! Nanoc loves you! <3')
run_nanoc_cmd(['view', '--port', '50385']) do
expect(Net::HTTP.get('127.0.0.1', '/', 50_385)).to eql('Hello there! Nanoc loves you! <3')
end
end
end
it 'does not serve other files as /' do
File.write('output/index.html666', 'Hello there! Nanoc loves you! <3')
run_nanoc_cmd(['view', '--port', '50385']) do
expect(Net::HTTP.get('127.0.0.1', '/', 50_385)).to eql("File not found: /\n")
end
end
it 'does not crash when output dir does not exist and --live-reload is given' do
FileUtils.rm_rf('output')
run_nanoc_cmd(['view', '--port', '50385', '--live-reload']) do
expect(Net::HTTP.get('127.0.0.1', '/', 50_385)).to eql("File not found: /\n")
end
end
it 'does not listen on non-local interfaces' do
addresses = Socket.getifaddrs.map(&:addr).select(&:ipv4?).map(&:ip_address)
non_local_addresses = addresses - ['127.0.0.1']
if non_local_addresses.empty?
skip 'Need non-local network interfaces for this spec'
end
run_nanoc_cmd(['view', '--port', '50385']) do
expect { Net::HTTP.get(non_local_addresses[0], '/', 50_385) }.to raise_error(Errno::ECONNREFUSED)
end
end
end
end
nanoc-4.11.0/nanoc/spec/nanoc/cli/error_handler_spec.rb000066400000000000000000000104341340050175000227520ustar00rootroot00000000000000# frozen_string_literal: true
describe Nanoc::CLI::ErrorHandler, stdio: true do
subject(:error_handler) { described_class.new }
describe '#forwards_stack_trace?' do
subject { error_handler.forwards_stack_trace? }
context 'Ruby 2.4' do
before do
expect(error_handler).to receive(:ruby_version).and_return('2.4.2')
end
it { is_expected.to be(false) }
end
context 'Ruby 2.5' do
before do
expect(error_handler).to receive(:ruby_version).and_return('2.5.0')
end
it { is_expected.to be(true) }
end
end
describe '#trivial?' do
subject { error_handler.trivial?(error) }
context 'LoadError of known gem' do
let(:error) do
begin
raise LoadError, 'cannot load such file -- nokogiri'
rescue LoadError => e
return e
end
end
it { is_expected.to be(true) }
end
context 'LoadError of unknown gem' do
let(:error) do
begin
raise LoadError, 'cannot load such file -- whatever'
rescue LoadError => e
return e
end
end
it { is_expected.to be(false) }
end
context 'random error' do
let(:error) do
begin
raise 'stuff'
rescue => e
return e
end
end
it { is_expected.to be(false) }
end
context 'Errno::EADDRINUSE' do
let(:error) do
begin
raise Errno::EADDRINUSE
rescue => e
return e
end
end
it { is_expected.to be(true) }
end
context 'GenericTrivial' do
let(:error) do
begin
raise Nanoc::Int::Errors::GenericTrivial, 'oh just a tiny thing'
rescue => e
return e
end
end
it { is_expected.to be(true) }
end
end
describe '#handle_error' do
subject { error_handler.handle_error(error, exit_on_error: exit_on_error) }
let(:error) do
begin
raise 'Bewm'
rescue => e
return e
end
end
let(:exit_on_error) { false }
describe 'exit behavior' do
context 'exit on error' do
let(:exit_on_error) { true }
it 'exits on error' do
expect { subject }.to raise_error(SystemExit)
end
end
context 'no exit on error' do
let(:exit_on_error) { false }
it 'does not exit on error' do
expect { subject }.not_to raise_error
end
end
end
describe 'printing behavior' do
context 'trivial error with no resolution' do
let(:error) do
begin
raise Nanoc::Int::Errors::GenericTrivial, 'asdf'
rescue => e
return e
end
end
it 'prints summary' do
expect { subject }.to output("\nError: asdf\n").to_stderr
end
end
context 'LoadError' do
let(:error) do
begin
raise LoadError, 'cannot load such file -- nokogiri'
rescue LoadError => e
return e
end
end
it 'prints summary' do
expected_output = "\n" + <<~OUT
Error: cannot load such file -- nokogiri
1. Add `gem 'nokogiri'` to your Gemfile
2. Run `bundle install`
3. Re-run this command
OUT
expect { subject }.to output(expected_output).to_stderr
end
end
context 'non-trivial error' do
# …
end
end
end
describe '#write_error_message' do
subject { error_handler.send(:write_error_message, $stdout, error, verbose: true) }
let(:error) do
begin
Nanoc::Int::Configuration.new(dir: '/oink', hash: { enable_output_diff: 'yeah' })
rescue => e
return e
end
end
example do
expect { subject }.to output("\n===== MESSAGE:\n\nJsonSchema::AggregateError: \n * #/enable_output_diff: For 'properties/enable_output_diff', \"yeah\" is not a boolean.\n").to_stdout
end
end
describe 'GEM_NAMES' do
example do
requires = Nanoc::Filter.all.flat_map(&:requires)
described =
Nanoc::CLI::ErrorHandler::GEM_NAMES.keys +
['erb', 'rdoc', 'nanoc/filters/sass/importer', 'nanoc/filters/sass/functions']
missing = requires - described
expect(missing).to be_empty
end
end
end
nanoc-4.11.0/nanoc/spec/nanoc/cli/stack_trace_writer_spec.rb000066400000000000000000000105751340050175000240110ustar00rootroot00000000000000# frozen_string_literal: true
describe Nanoc::CLI::StackTraceWriter do
subject(:writer) do
described_class.new(io, forwards: forwards)
end
let(:io) { StringIO.new }
let(:forwards) { true }
describe '#write' do
let(:exception) do
backtrace_generator = lambda do |af|
if af.zero?
raise 'finally!'
else
backtrace_generator.call(af - 1)
end
end
begin
backtrace_generator.call(3)
rescue => e
return e
end
end
subject { writer.write(exception, verbose: verbose) }
let(:verbose) { false }
context 'backwards' do
let(:forwards) { false }
context 'verbose' do
let(:verbose) { true }
it 'starts with zero' do
expect { subject }
.to change { io.string }
.from('')
.to(start_with(' 0. '))
end
it 'has more recent stack frames at the top' do
expect { subject }
.to change { io.string }
.from('')
.to(match(%r{^ 0\. (C:)?/.+/spec/nanoc/cli/stack_trace_writer_spec\.rb:\d+.*$\n 1\. (C:)?/.+/spec/nanoc/cli/stack_trace_writer_spec\.rb:\d}m))
end
it 'has more than 10 stack frames' do
expect { subject }
.to change { io.string }
.from('')
.to(match(%r{^ 11\. }))
end
it 'does not contain a see-more explanation' do
subject
expect(io.string).not_to match(/crash\.log/)
end
end
context 'not verbose' do
let(:verbose) { false }
it 'starts with zero' do
expect { subject }
.to change { io.string }
.from('')
.to(start_with(' 0. '))
end
it 'has more recent stack frames at the top' do
expect { subject }
.to change { io.string }
.from('')
.to(match(%r{^ 0\. (C:)?/.+/spec/nanoc/cli/stack_trace_writer_spec\.rb:\d+.*$\n 1\. (C:)?/.+/spec/nanoc/cli/stack_trace_writer_spec\.rb:\d}m))
end
it 'has not more than 10 stack frames' do
subject
expect(io.string).not_to match(/^ 11\. /)
end
it 'does not contain a see-more explanation' do
subject
expect(io.string).to include(" lines omitted (see crash.log for details)\n")
end
end
end
context 'forwards' do
let(:forwards) { true }
context 'verbose' do
let(:verbose) { true }
it 'ends with most recent line' do
expect { subject }
.to change { io.string }
.from('')
.to(match(%r{^ 1\. from (C:)?/.+/spec/nanoc/cli/stack_trace_writer_spec\.rb:\d+.*$\n (C:)?/.+/spec/nanoc/cli}m))
end
it 'has more recent stack frames at the bottom' do
expect { subject }
.to change { io.string }
.from('')
.to(match(%r{^ 2\. from (C:)?/.+/spec/nanoc/cli/stack_trace_writer_spec\.rb:\d+.*$\n 1\. from (C:)?/.+/spec/nanoc/cli/stack_trace_writer_spec\.rb:\d}m))
end
it 'has more than 10 stack frames' do
expect { subject }
.to change { io.string }
.from('')
.to(match(%r{^ 11\. from }))
end
it 'does not contain a see-more explanation' do
subject
expect(io.string).not_to match(/crash\.log/)
end
end
context 'not verbose' do
let(:verbose) { false }
it 'ends with most recent line' do
expect { subject }
.to change { io.string }
.from('')
.to(match(%r{^ 1\. from (C:)?/.+/spec/nanoc/cli/stack_trace_writer_spec\.rb:\d+.*$\n (C:)?/.+/spec/nanoc/cli}m))
end
it 'has more recent stack frames at the top' do
expect { subject }
.to change { io.string }
.from('')
.to(match(%r{^ 2\. from (C:)?/.+/spec/nanoc/cli/stack_trace_writer_spec\.rb:\d+.*$\n 1\. from (C:)?/.+/spec/nanoc/cli/stack_trace_writer_spec\.rb:\d}m))
end
it 'has not more than 10 stack frames' do
subject
expect(io.string).not_to match(/^ 11\. from /)
end
it 'does not contain a see-more explanation' do
subject
expect(io.string).to include(" lines omitted (see crash.log for details)\n")
end
end
end
end
end
nanoc-4.11.0/nanoc/spec/nanoc/cli/stream_cleaners/000077500000000000000000000000001340050175000217325ustar00rootroot00000000000000nanoc-4.11.0/nanoc/spec/nanoc/cli/stream_cleaners/utf8_spec.rb000066400000000000000000000004201340050175000241530ustar00rootroot00000000000000# frozen_string_literal: true
describe Nanoc::CLI::StreamCleaners::UTF8 do
subject { described_class.new }
it 'handles all cases' do
expect(subject.clean('┼─ “© Denis” ‘and others…’ ─┼')).to eq('+- "(c) Denis" \'and others...\' -+')
end
end
nanoc-4.11.0/nanoc/spec/nanoc/cli_spec.rb000066400000000000000000000036101340050175000201220ustar00rootroot00000000000000# frozen_string_literal: true
describe Nanoc::CLI do
let(:all_commands) do
ObjectSpace.each_object(Cri::Command)
end
let(:exceptions) do
# FIXME: [Nanoc 5] Get rid of these exceptions
[
['deploy', ['C']],
['help', ['v']],
['check', ['d']],
]
end
def ancestors_of_command(command)
if command.is_a?(Cri::Command)
[command] + ancestors_of_command(command.supercommand)
else
[]
end
end
def short_options_for_command(command)
ancestors = ancestors_of_command(command)
ancestors.flat_map { |a| a.option_definitions.to_a.map(&:short) }.compact
end
it 'has no commands that have conflicting options' do
all_commands.each do |command|
short_options = short_options_for_command(command)
duplicate_options = short_options.select { |o| short_options.count(o) > 1 }.uniq
next if exceptions.include?([command.name, duplicate_options])
expect(duplicate_options).to(
be_empty,
"The #{command.name} command’s option shorthands #{duplicate_options.uniq} are used by multiple options",
)
end
end
describe '#enable_ansi_colors?' do
subject { described_class.enable_ansi_colors?(io) }
context 'TTY' do
let(:io) { double(:io, tty?: true) }
context 'NO_COLOR set' do
before do
allow(ENV).to receive(:key?).with('NO_COLOR').and_return(true)
end
it { is_expected.to be(false) }
end
context 'NO_COLOR not set' do
it { is_expected.to be(true) }
end
end
context 'no TTY' do
let(:io) { double(:io, tty?: false) }
context 'NO_COLOR set' do
before do
allow(ENV).to receive(:key?).with('NO_COLOR').and_return(true)
end
it { is_expected.to be(false) }
end
context 'NO_COLOR not set' do
it { is_expected.to be(false) }
end
end
end
end
nanoc-4.11.0/nanoc/spec/nanoc/data_sources/000077500000000000000000000000001340050175000204705ustar00rootroot00000000000000nanoc-4.11.0/nanoc/spec/nanoc/data_sources/filesystem/000077500000000000000000000000001340050175000226545ustar00rootroot00000000000000nanoc-4.11.0/nanoc/spec/nanoc/data_sources/filesystem/parser_spec.rb000066400000000000000000000232411340050175000255110ustar00rootroot00000000000000# frozen_string_literal: true
describe Nanoc::DataSources::Filesystem::Parser do
subject(:parser) { described_class.new(config: config) }
let(:config) do
Nanoc::Int::Configuration.new(dir: Dir.getwd).with_defaults
end
describe '#call' do
subject { parser.call(content_filename, meta_filename) }
let(:content_filename) { nil }
let(:meta_filename) { nil }
context 'only meta file' do
let(:meta_filename) { Tempfile.open('test') { |fn| fn << 'asdf' }.path }
before do
File.write(meta_filename, meta)
end
context 'simple metadata' do
let(:meta) { "foo: bar\n" }
it 'reads attributes' do
expect(subject.attributes).to eq('foo' => 'bar')
end
it 'has no content' do
expect(subject.content).to eq('')
end
end
context 'UTF-8 bom' do
let(:meta) { [0xEF, 0xBB, 0xBF].map(&:chr).join + "foo: bar\r\n" }
it 'strips UTF-8 BOM' do
expect(subject.attributes).to eq('foo' => 'bar')
end
it 'has no content' do
expect(subject.content).to eq('')
end
end
context 'CRLF' do
let(:meta) { "foo: bar\r\n" }
it 'handles CR+LF line endings' do
expect(subject.attributes).to eq('foo' => 'bar')
end
it 'has no content' do
expect(subject.content).to eq('')
end
end
context 'metadata is empty' do
let(:meta) { '' }
it 'has no attributes' do
expect(subject.attributes).to eq({})
end
it 'has no content' do
expect(subject.content).to eq('')
end
end
context 'metadata is not hash' do
let(:meta) { "- stuff\n" }
it 'raises' do
expect { subject }
.to raise_error(Nanoc::DataSources::Filesystem::Errors::InvalidMetadata, /has invalid metadata \(expected key-value pairs, found Array instead\)/)
end
end
end
context 'only content file' do
let(:content_filename) { Tempfile.open('test') { |fn| fn << 'asdf' }.path }
before do
File.write(content_filename, content)
end
context 'no metadata section' do
context 'simple' do
let(:content) { "Hello!\n" }
it 'has no attributes' do
expect(subject.attributes).to eq({})
end
it 'has content' do
expect(subject.content).to eq("Hello!\n")
end
end
context 'UTF-8 bom' do
let(:content) { [0xEF, 0xBB, 0xBF].map(&:chr).join + "Hello!\n" }
it 'has no attributes' do
expect(subject.attributes).to eq({})
end
it 'strips UTF-8 BOM' do
expect(subject.content).to eq("Hello!\n")
end
end
context 'CRLF' do
let(:content) { "Hello!\r\n" }
it 'has no attributes' do
expect(subject.attributes).to eq({})
end
it 'retains CR+LF' do
# FIXME: Is this the right thing to do?
expect(subject.content).to eq("Hello!\r\n")
end
end
end
context 'metadata section' do
context 'three dashes' do
let(:content) { "---\ntitle: Welcome\n---\nHello!\n" }
it 'has attributes' do
expect(subject.attributes).to eq('title' => 'Welcome')
end
it 'has content' do
expect(subject.content).to eq("Hello!\n")
end
end
context 'five dashes' do
let(:content) { "-----\ntitle: Welcome\n-----\nHello!\n" }
it 'has attributes' do
expect(subject.attributes).to eq('title' => 'Welcome')
end
it 'has content' do
expect(subject.content).to eq("Hello!\n")
end
end
context 'trailing spaces' do
let(:content) { "--- \ntitle: Welcome \n--- \nHello! \n" }
it 'has attributes' do
expect(subject.attributes).to eq('title' => 'Welcome')
end
it 'has content' do
expect(subject.content).to eq("Hello! \n")
end
end
context 'diff' do
let(:content) { "--- a/foo\n+++ b/foo\nblah blah\n" }
it 'has no attributes' do
expect(subject.attributes).to eq({})
end
it 'has content' do
expect(subject.content).to eq(content)
end
end
context 'separator not at beginning' do
let(:content) { "foo\n---\ntitle: Welcome\n---\nStuff\n" }
it 'has no attributes' do
expect(subject.attributes).to eq({})
end
it 'has content' do
expect(subject.content).to eq(content)
end
end
context 'unterminated metadata section' do
let(:content) { "---\ntitle: Welcome\n" }
it 'raises' do
expect { subject }.to raise_error(Nanoc::DataSources::Filesystem::Errors::InvalidFormat)
end
end
context 'non-hash metadata section' do
let(:content) { "---\nWelcome\n---\nHello!\n" }
it 'raises' do
expect { subject }.to raise_error(Nanoc::DataSources::Filesystem::Errors::InvalidMetadata)
end
end
context 'empty metadata section' do
let(:content) { "---\n---\nHello!\n" }
it 'has no attributes' do
expect(subject.attributes).to eq({})
end
it 'has content' do
expect(subject.content).to eq("Hello!\n")
end
end
context 'leading newline' do
let(:content) { "---\ntitle: Welcome\n---\n\nHello!\n" }
it 'has attributes' do
expect(subject.attributes).to eq('title' => 'Welcome')
end
it 'has content' do
expect(subject.content).to eq("Hello!\n")
end
end
context 'two leading newlines' do
let(:content) { "---\ntitle: Welcome\n---\n\n\nHello!\n" }
it 'has attributes' do
expect(subject.attributes).to eq('title' => 'Welcome')
end
it 'has content with one leading newline' do
expect(subject.content).to eq("\nHello!\n")
end
end
context 'no content' do
let(:content) { "---\ntitle: Welcome\n---\n" }
it 'has attributes' do
expect(subject.attributes).to eq('title' => 'Welcome')
end
it 'has no content' do
expect(subject.content).to eq('')
end
end
context 'UTF-8 bom' do
let(:content) { [0xEF, 0xBB, 0xBF].map(&:chr).join + "---\ntitle: Welcome\n---\nHello!\n" }
it 'has attributes' do
expect(subject.attributes).to eq('title' => 'Welcome')
end
it 'strips UTF-8 BOM' do
expect(subject.content).to eq("Hello!\n")
end
end
context 'CRLF' do
let(:content) { "---\r\ntitle: Welcome\r\n---\r\nHello!\r\n" }
it 'has attributes' do
expect(subject.attributes).to eq('title' => 'Welcome')
end
it 'retains CR+LF' do
# FIXME: Is this the right thing to do?
expect(subject.content).to eq("Hello!\r\n")
end
end
context 'four dashes' do
let(:content) { "----\ntitle: Welcome\n----\nHello!\n" }
it 'has no attributes' do
expect(subject.attributes).to eq({})
end
it 'has unparsed content' do
expect(subject.content).to eq(content)
end
end
context 'additional separators' do
let(:content) { "---\ntitle: Welcome\n---\nHello!\n---\nStuff\n" }
it 'has attributes' do
expect(subject.attributes).to eq('title' => 'Welcome')
end
it 'has content' do
expect(subject.content).to eq("Hello!\n---\nStuff\n")
end
end
end
end
context 'meta and content file' do
let(:content_filename) { Tempfile.open('test') { |fn| fn << 'asdf' }.path }
let(:meta_filename) { Tempfile.open('test') { |fn| fn << 'asdf' }.path }
before do
File.write(content_filename, content)
File.write(meta_filename, meta)
end
context 'simple' do
let(:content) { "Hello\n" }
let(:meta) { "title: Welcome\n" }
it 'has attributes' do
expect(subject.attributes).to eq('title' => 'Welcome')
end
it 'has content' do
expect(subject.content).to eq("Hello\n")
end
end
context 'apparent metadata section' do
let(:content) { "---\nauthor: Denis\n---\nHello!\n" }
let(:meta) { "title: Welcome\n" }
it 'has attributes' do
expect(subject.attributes).to eq('title' => 'Welcome')
end
it 'does not parse content' do
expect(subject.content).to eq(content)
end
end
context 'CRLF' do
let(:content) { "Hello!\r\n" }
let(:meta) { "title: Welcome\r\n" }
it 'has attributes' do
expect(subject.attributes).to eq('title' => 'Welcome')
end
it 'has content' do
# FIXME: Is this the right thing to do?
expect(subject.content).to eq("Hello!\r\n")
end
end
context 'UTF-8 bom' do
let(:content) { [0xEF, 0xBB, 0xBF].map(&:chr).join + "Hello!\n" }
let(:meta) { [0xEF, 0xBB, 0xBF].map(&:chr).join + "title: Welcome\n" }
it 'has attributes' do
expect(subject.attributes).to eq('title' => 'Welcome')
end
it 'has content' do
expect(subject.content).to eq("Hello!\n")
end
end
end
end
end
nanoc-4.11.0/nanoc/spec/nanoc/data_sources/filesystem/tools_spec.rb000066400000000000000000000052171340050175000253600ustar00rootroot00000000000000# frozen_string_literal: true
describe Nanoc::DataSources::Filesystem::Tools do
describe '.read_file' do
subject { described_class.read_file(filename, config: config) }
let(:filename) { 'foo.dat' }
let(:config) { {} }
context 'file does not exist' do
it 'errors' do
expect { subject }
.to raise_error(
Nanoc::DataSources::Filesystem::Errors::FileUnreadable,
/^Could not read foo.dat:/,
)
end
end
context 'file exists as ISO-8859-1' do
before do
File.write(filename, 'élève'.encode('ISO-8859-1'))
end
context 'no config' do
it 'errors' do
expect { subject }
.to raise_error(
Nanoc::DataSources::Filesystem::Errors::InvalidEncoding,
'Could not read foo.dat because the file is not valid UTF-8.',
)
end
end
context 'config with correct encoding' do
let(:config) do
{ encoding: 'ISO-8859-1' }
end
it { is_expected.to eq('élève') }
its(:encoding) { is_expected.to eq(Encoding::UTF_8) }
end
context 'config with incorrect encoding' do
let(:config) do
{ encoding: 'UTF-16' }
end
it 'errors' do
expect { subject }
.to raise_error(
Nanoc::DataSources::Filesystem::Errors::InvalidEncoding,
'Could not read foo.dat because the file is not valid UTF-16.',
)
end
end
end
context 'file exists as UTF-8' do
before do
File.write(filename, 'élève'.encode('UTF-8'))
end
context 'no config' do
it { is_expected.to eq('élève') }
its(:encoding) { is_expected.to eq(Encoding::UTF_8) }
end
context 'config with correct encoding' do
let(:config) do
{ encoding: 'UTF-8' }
end
it { is_expected.to eq('élève') }
its(:encoding) { is_expected.to eq(Encoding::UTF_8) }
end
context 'config with incorrect encoding' do
let(:config) do
{ encoding: 'UTF-16' }
end
it 'errors' do
expect { subject }
.to raise_error(
Nanoc::DataSources::Filesystem::Errors::InvalidEncoding,
'Could not read foo.dat because the file is not valid UTF-16.',
)
end
end
end
context 'file exists as UTF-8 wit BOM' do
before do
File.write(filename, "\xEF\xBB\xBFélève".encode('UTF-8'))
end
it { is_expected.to eq('élève') }
its(:encoding) { is_expected.to eq(Encoding::UTF_8) }
end
end
end
nanoc-4.11.0/nanoc/spec/nanoc/data_sources/filesystem_spec.rb000066400000000000000000000233101340050175000242120ustar00rootroot00000000000000# frozen_string_literal: true
describe Nanoc::DataSources::Filesystem, site: true do
let(:data_source) { Nanoc::DataSources::Filesystem.new(site.config, nil, nil, params) }
let(:params) { {} }
let(:site) { Nanoc::Int::SiteLoader.new.new_from_cwd }
before { Timecop.freeze(now) }
after { Timecop.return }
let(:now) { Time.local(2008, 1, 2, 14, 5, 0) }
describe '#load_objects' do
subject { data_source.send(:load_objects, 'foo', klass) }
let(:klass) { raise 'override me' }
context 'items' do
let(:klass) { Nanoc::Int::Item }
context 'no files' do
it 'loads nothing' do
expect(subject).to be_empty
end
end
context 'one textual file' do
before do
FileUtils.mkdir_p('foo')
File.write('foo/bar.html', "---\nnum: 1\n---\ntest 1")
FileUtils.touch('foo/bar.html', mtime: now)
end
let(:expected_attributes) do
{
content_filename: 'foo/bar.html',
extension: 'html',
filename: 'foo/bar.html',
meta_filename: nil,
mtime: now,
num: 1,
}
end
it 'loads that file' do
expect(subject.size).to eq(1)
expect(subject[0].content.string).to eq('test 1')
expect(subject[0].attributes).to eq(expected_attributes)
expect(subject[0].identifier).to eq(Nanoc::Identifier.new('/bar/', type: :legacy))
expect(subject[0].checksum_data).to be_nil
expect(subject[0].attributes_checksum_data).to be_a(String)
expect(subject[0].attributes_checksum_data.size).to eq(20)
expect(subject[0].content_checksum_data).to be_a(String)
expect(subject[0].content_checksum_data.size).to eq(20)
end
context 'split files' do
let(:block) do
lambda do
FileUtils.mkdir_p('foo')
File.write('foo/bar.html', 'test 1')
FileUtils.touch('foo/bar.html', mtime: now)
File.write('foo/bar.yaml', "---\nnum: 1\n")
FileUtils.touch('foo/bar.yaml', mtime: now)
end
end
it 'has a different attributes checksum' do
expect(block).to change { data_source.send(:load_objects, 'foo', klass)[0].attributes_checksum_data }
end
it 'has the same content checksum' do
expect(block).not_to change { data_source.send(:load_objects, 'foo', klass)[0].content_checksum_data }
end
end
end
context 'one binary file' do
before do
FileUtils.mkdir_p('foo')
File.write('foo/bar.dat', "---\nnum: 1\n---\ntest 1")
FileUtils.touch('foo/bar.dat', mtime: now)
end
let(:expected_attributes) do
{
content_filename: 'foo/bar.dat',
extension: 'dat',
filename: 'foo/bar.dat',
meta_filename: nil,
mtime: now,
}
end
it 'loads that file' do
expect(subject.size).to eq(1)
expect(subject[0].content).to be_a(Nanoc::Int::BinaryContent)
expect(subject[0].attributes).to eq(expected_attributes)
expect(subject[0].identifier).to eq(Nanoc::Identifier.new('/bar/', type: :legacy))
expect(subject[0].checksum_data).to be_nil
expect(subject[0].attributes_checksum_data).to be_a(String)
expect(subject[0].attributes_checksum_data.size).to eq(20)
end
it 'has no content checksum data' do
expect(subject[0].content_checksum_data).to be_nil
end
end
context 'two content files (no inline metadata) with one meta file' do
let(:params) { { identifier_type: 'full' } }
before do
FileUtils.mkdir_p('foo')
File.write('foo/a.txt', 'hi')
File.write('foo/a.md', 'ho')
File.write('foo/a.yaml', 'title: Aaah')
end
it 'errors' do
expect { subject }
.to raise_error(
Nanoc::Int::Errors::AmbiguousMetadataAssociation,
'There are multiple content files (foo/a.txt, foo/a.md) that could match the file containing metadata (foo/a.yaml).',
)
end
end
context 'two content files (one has inline metadata) with one meta file' do
let(:params) { { identifier_type: 'full' } }
before do
FileUtils.mkdir_p('foo')
File.write('foo/a.txt', "---\ntitle: Hi\n---\n\nhi")
File.write('foo/a.md', 'ho')
File.write('foo/a.yaml', 'title: Aaah')
end
it 'assigns metadata to the file that doesn’t have any yet' do
expect(subject.size).to eq(2)
items = subject.sort_by { |i| i.identifier.to_s }
expect(items[0].content).to be_a(Nanoc::Int::TextualContent)
expect(items[0].identifier).to eq(Nanoc::Identifier.new('/a.md', type: :full))
expect(items[0].attributes[:title]).to eq('Aaah')
expect(items[1].content).to be_a(Nanoc::Int::TextualContent)
expect(items[1].identifier).to eq(Nanoc::Identifier.new('/a.txt', type: :full))
expect(items[1].attributes[:title]).to eq('Hi')
end
end
context 'two content files (both have inline metadata) with one meta file' do
let(:params) { { identifier_type: 'full' } }
before do
FileUtils.mkdir_p('foo')
File.write('foo/a.txt', "---\ntitle: Hi\n---\n\nhi")
File.write('foo/a.md', "---\ntitle: Ho\n---\n\nho")
File.write('foo/a.yaml', 'title: Aaah')
end
it 'errors' do
expect { subject }
.to raise_error(
Nanoc::Int::Errors::AmbiguousMetadataAssociation,
'There are multiple content files (foo/a.txt, foo/a.md) that could match the file containing metadata (foo/a.yaml).',
)
end
end
context 'two content files (both have inline metadata) with no meta file' do
let(:params) { { identifier_type: 'full' } }
before do
FileUtils.mkdir_p('foo')
File.write('foo/a.txt', "---\ntitle: Hi\n---\n\nhi")
File.write('foo/a.md', "---\ntitle: Ho\n---\n\nho")
end
it 'uses inline metadata' do
expect(subject.size).to eq(2)
items = subject.sort_by { |i| i.identifier.to_s }
expect(items[0].content).to be_a(Nanoc::Int::TextualContent)
expect(items[0].identifier).to eq(Nanoc::Identifier.new('/a.md', type: :full))
expect(items[0].attributes[:title]).to eq('Ho')
expect(items[1].content).to be_a(Nanoc::Int::TextualContent)
expect(items[1].identifier).to eq(Nanoc::Identifier.new('/a.txt', type: :full))
expect(items[1].attributes[:title]).to eq('Hi')
end
end
context 'two content files (neither have inline metadata) with no meta file' do
let(:params) { { identifier_type: 'full' } }
before do
FileUtils.mkdir_p('foo')
File.write('foo/a.txt', 'hi')
File.write('foo/a.md', 'ho')
end
it 'uses no metadata' do
expect(subject.size).to eq(2)
items = subject.sort_by { |i| i.identifier.to_s }
expect(items[0].content).to be_a(Nanoc::Int::TextualContent)
expect(items[0].identifier).to eq(Nanoc::Identifier.new('/a.md', type: :full))
expect(items[0].attributes[:title]).to be_nil
expect(items[1].content).to be_a(Nanoc::Int::TextualContent)
expect(items[1].identifier).to eq(Nanoc::Identifier.new('/a.txt', type: :full))
expect(items[1].attributes[:title]).to be_nil
end
end
context 'one content file (with inline metadata) and a meta file' do
let(:params) { { identifier_type: 'full' } }
before do
FileUtils.mkdir_p('foo')
File.write('foo/a.txt', "---\ntitle: Hi\n---\n\nhi")
File.write('foo/a.yaml', 'author: Denis')
end
it 'uses only metadata from meta file' do
expect(subject.size).to eq(1)
expect(subject[0].content).to be_a(Nanoc::Int::TextualContent)
expect(subject[0].content.string).to eq("---\ntitle: Hi\n---\n\nhi")
expect(subject[0].identifier).to eq(Nanoc::Identifier.new('/a.txt', type: :full))
expect(subject[0].attributes[:title]).to be_nil
expect(subject[0].attributes[:author]).to eq('Denis')
end
end
end
end
describe '#item_changes' do
subject { data_source.item_changes }
before do
if Nanoc.on_windows?
skip 'nanoc-live is not currently supported on Windows'
end
end
it 'returns a stream' do
expect(subject).to be_a(Nanoc::ChangesStream)
end
it 'contains one element after changing' do
FileUtils.mkdir_p('content')
enum = SlowEnumeratorTools.buffer(subject.to_enum, 1)
q = SizedQueue.new(1)
Thread.new { q << enum.take(1).first }
# FIXME: sleep is ugly
sleep 0.3
File.write('content/wat.md', 'stuff')
expect(q.pop).to eq(:unknown)
subject.stop
end
end
describe '#layout_changes' do
subject { data_source.layout_changes }
before do
if Nanoc.on_windows?
skip 'nanoc-live is not currently supported on Windows'
end
end
it 'returns a stream' do
expect(subject).to be_a(Nanoc::ChangesStream)
end
it 'contains one element after changing' do
FileUtils.mkdir_p('layouts')
enum = SlowEnumeratorTools.buffer(subject.to_enum, 1)
q = SizedQueue.new(1)
Thread.new { q << enum.take(1).first }
# FIXME: sleep is ugly
sleep 0.3
File.write('layouts/wat.md', 'stuff')
expect(q.pop).to eq(:unknown)
subject.stop
end
end
end
nanoc-4.11.0/nanoc/spec/nanoc/deploying/000077500000000000000000000000001340050175000200065ustar00rootroot00000000000000nanoc-4.11.0/nanoc/spec/nanoc/deploying/fog_spec.rb000066400000000000000000000127061340050175000221260ustar00rootroot00000000000000# frozen_string_literal: true
describe Nanoc::Deploying::Deployers::Fog, stdio: true do
let(:deployer) do
Nanoc::Deploying::Deployers::Fog.new(
'output/',
config,
dry_run: is_dry_run,
)
end
let(:is_dry_run) { false }
let(:config) do
{
bucket: 'bucky',
provider: 'local',
local_root: 'remote',
}
end
before do
# create output
FileUtils.mkdir_p('output')
FileUtils.mkdir_p('output/etc')
File.open('output/woof', 'w') { |io| io.write 'I am a dog!' }
File.open('output/etc/meow', 'w') { |io| io.write 'I am a cat!' }
# create local cloud
FileUtils.mkdir_p('remote')
end
subject { deployer.run }
shared_examples 'no effective deploy' do
it 'does not modify remote' do
expect { subject }.not_to change { Dir['remote/**/*'].sort }
end
end
shared_examples 'effective deploy' do
it 'modifies remote' do
expect { subject }.to change { Dir['remote/**/*'].sort }
.to([
'remote/bucky',
'remote/bucky/etc',
'remote/bucky/etc/meow',
'remote/bucky/woof',
])
end
end
context 'dry run' do
let(:is_dry_run) { true }
before do
FileUtils.mkdir_p('remote/bucky')
FileUtils.mkdir_p('remote/bucky/tiny')
File.write('remote/bucky/pig', 'oink?')
File.write('remote/bucky/tiny/piglet', 'little oink?')
end
include_examples 'no effective deploy'
context 'with CDN ID' do
let(:config) { super().merge(cdn_id: 'donkey-cdn') }
let(:cdn) { Object.new }
let(:distribution) { Object.new }
it 'does not actually invalidate' do
expect(::Fog::CDN).to receive(:new).with(provider: 'local', local_root: 'remote').and_return(cdn)
expect(cdn).to receive(:get_distribution).with('donkey-cdn').and_return(distribution)
subject
end
end
end
context 'effective run' do
include_examples 'effective deploy'
context 'custom path' do
context 'custom path ends with /' do
let(:config) do
super().merge(path: 'foo/')
end
it 'raises' do
expect { subject }.to raise_error('The path `foo/` is not supposed to have a trailing slash')
end
end
context 'custom path does not end with /' do
let(:config) do
super().merge(path: 'foo')
end
it 'modifies remote' do
expect { subject }.to change { Dir['remote/**/*'].sort }
.to([
'remote/bucky',
'remote/bucky/foo',
'remote/bucky/foo/etc',
'remote/bucky/foo/etc/meow',
'remote/bucky/foo/woof',
])
end
end
end
context 'bucket already exists' do
before do
FileUtils.mkdir_p('remote/bucky')
end
include_examples 'effective deploy'
end
context 'remote contains stale file at root' do
before do
FileUtils.mkdir_p('remote/bucky')
File.write('remote/bucky/pig', 'oink?')
end
include_examples 'effective deploy'
it 'does not contain stale files' do
subject
expect(Dir['remote/**/*'].sort).not_to include('remote/bucky/pig')
end
end
context 'remote contains stale file in subdirectory' do
before do
FileUtils.mkdir_p('remote/bucky/secret')
File.write('remote/bucky/secret/pig', 'oink?')
end
include_examples 'effective deploy'
it 'does not contain stale files' do
subject
expect(Dir['remote/**/*'].sort).not_to include('remote/bucky/secret/pig')
end
end
context 'with CDN ID' do
let(:config) { super().merge(cdn_id: 'donkey-cdn') }
let(:cdn) { Object.new }
let(:distribution) { Object.new }
it 'invalidates' do
expect(::Fog::CDN).to receive(:new).with(provider: 'local', local_root: 'remote').and_return(cdn)
expect(cdn).to receive(:get_distribution).with('donkey-cdn').and_return(distribution)
expect(cdn).to receive(:post_invalidation).with(distribution, contain_exactly('etc/meow', 'woof'))
subject
end
end
context 'remote list consists of truncated sets' do
before do
expect(::Fog::Storage).to receive(:new).and_return(fog_storage)
expect(fog_storage).to receive(:directories).and_return(directories)
expect(directories).to receive(:get).and_return(directory)
allow(directory).to receive(:files).and_return(files)
expect(files).to receive(:get).with('stray').and_return(file_stray).ordered
expect(files).to receive(:each)
.and_yield(double(:woof, key: 'woof'))
.and_yield(double(:meow, key: 'etc/meow'))
.and_yield(double(:stray, key: 'stray'))
expect(file_stray).to receive(:destroy)
expect(files).to receive(:create).with(key: 'woof', body: anything, public: true) do
FileUtils.mkdir_p('remote/bucky')
File.write('remote/bucky/woof', 'hi')
end
expect(files).to receive(:create).with(key: 'etc/meow', body: anything, public: true) do
FileUtils.mkdir_p('remote/bucky/etc')
File.write('remote/bucky/etc/meow', 'hi')
end
end
let(:fog_storage) { double(:fog_storage) }
let(:directories) { double(:directories) }
let(:directory) { double(:directory) }
let(:files) { double(:files) }
let(:file_stray) { double(:file_stray) }
include_examples 'effective deploy'
end
end
end
nanoc-4.11.0/nanoc/spec/nanoc/deploying/git_spec.rb000066400000000000000000000207341340050175000221360ustar00rootroot00000000000000# frozen_string_literal: true
describe Nanoc::Deploying::Deployers::Git, stdio: true do
let(:deployer) { described_class.new(output_dir, options, dry_run: dry_run) }
subject { deployer.run }
let(:output_dir) { 'output/' }
let(:options) { remote_options.merge(branch_options).merge(forced_options) }
let(:dry_run) { false }
let(:remote_options) { {} }
let(:branch_options) { {} }
let(:forced_options) { {} }
def run_and_get_stdout(*args)
stdout = +''
stderr = +''
piper = Nanoc::Extra::Piper.new(stdout: stdout, stderr: stderr)
piper.run(args, '')
stdout
end
def add_changes_to_remote
system('git', 'init', '--quiet', 'rere_tmp')
Dir.chdir('rere_tmp') do
system('git', 'config', 'user.name', 'Zebra Platypus')
system('git', 'config', 'user.email', 'zebra@platypus.example.com')
system('git', 'remote', 'add', 'origin', '../rere')
File.write('evil.txt', 'muaha')
system('git', 'add', 'evil.txt')
system('git', 'commit', '--quiet', '-m', 'muaha')
system('git', 'checkout', '--quiet', '-b', 'giraffe')
system('git', 'push', '--quiet', 'origin', 'master')
system('git', 'push', '--quiet', 'origin', 'giraffe')
end
end
def rev_list
run_and_get_stdout('git', 'rev-list', '--objects', '--all')
end
shared_examples 'branch configured properly' do
context 'clean working copy' do
it 'does not commit or push' do
subject
end
end
context 'non-clean working copy' do
before do
Dir.chdir(output_dir) { File.write('hello.txt', 'Hi there') }
end
shared_examples 'successful push' do
context 'no dry run' do
it 'outputs status' do
expect { subject }
.to output(/Deploying via Git to branch “#{branch}” on remote “#{remote}”…/)
.to_stdout
end
it 'makes a change in the local repo' do
expect { subject }
.to change { Dir.chdir(output_dir) { rev_list } }
.from(not_match(/^[a-f0-9]{40} hello\.txt$/))
.to(match(/^[a-f0-9]{40} hello\.txt$/))
expect(Dir.chdir(output_dir) { run_and_get_stdout('git', 'show', branch) })
.to match(/^Author: Nanoc <>$/)
end
it 'makes a change in the remote repo' do
expect { subject }
.to change { Dir.chdir('rere') { rev_list } }
.from(not_match(/^[a-f0-9]{40} hello\.txt$/))
.to(match(/^[a-f0-9]{40} hello\.txt$/))
end
end
context 'dry run' do
let(:dry_run) { true }
it 'makes a change in the local repo' do
expect { subject }
.not_to change { Dir.chdir(output_dir) { rev_list } }
end
it 'makes a change in the remote repo' do
expect { subject }
.not_to change { Dir.chdir('rere') { rev_list } }
end
end
end
context 'forced' do
let(:forced_options) { { forced: true } }
context 'remote has no other changes' do
include_examples 'successful push'
end
context 'remote has other changes' do
before { add_changes_to_remote }
include_examples 'successful push'
end
end
context 'not forced (implicit)' do
let(:forced_options) { {} }
context 'remote has no other changes' do
include_examples 'successful push'
end
context 'remote has other changes' do
before { add_changes_to_remote }
it 'raises' do
expect { subject }.to raise_error(Nanoc::Extra::Piper::Error)
end
end
end
context 'not forced (explicit)' do
let(:forced_options) { { forced: false } }
context 'remote has no other changes' do
include_examples 'successful push'
end
context 'remote has other changes' do
before { add_changes_to_remote }
it 'raises' do
expect { subject }.to raise_error(Nanoc::Extra::Piper::Error)
end
end
end
end
end
shared_examples 'remote configured properly' do
before do
system('git', 'init', '--bare', '--quiet', 'rere')
end
context 'default branch' do
context 'branch does not exist' do
it 'raises' do
expect { subject }.to raise_error(
Nanoc::Deploying::Deployers::Git::Errors::BranchDoesNotExist,
'The branch to deploy, master, does not exist.',
)
end
end
context 'branch exists' do
before do
Dir.chdir(output_dir) do
system('git', 'commit', '--quiet', '-m', 'init', '--allow-empty')
end
end
let(:branch) { 'master' }
include_examples 'branch configured properly'
end
end
context 'custom branch' do
let(:branch) { 'giraffe' }
let(:branch_options) { { branch: branch } }
context 'branch does not exist' do
it 'raises' do
expect { subject }.to raise_error(
Nanoc::Deploying::Deployers::Git::Errors::BranchDoesNotExist,
'The branch to deploy, giraffe, does not exist.',
)
end
end
context 'branch exists' do
before do
Dir.chdir(output_dir) do
system('git', 'commit', '--quiet', '-m', 'init', '--allow-empty')
system('git', 'branch', 'giraffe')
end
end
include_examples 'branch configured properly'
end
end
end
context 'output dir does not exist' do
it 'raises' do
expect { subject }.to raise_error(
Nanoc::Deploying::Deployers::Git::Errors::OutputDirDoesNotExist,
'The directory to deploy, output/, does not exist.',
)
end
end
context 'output dir exists' do
before do
FileUtils.mkdir_p(output_dir)
end
context 'output dir is not a Git repo' do
it 'raises' do
expect { subject }.to raise_error(
Nanoc::Deploying::Deployers::Git::Errors::OutputDirIsNotAGitRepo,
'The directory to deploy, output/, is not a Git repository.',
)
end
end
context 'output dir is a Git repo' do
before do
Dir.chdir(output_dir) do
system('git', 'init', '--quiet')
system('git', 'config', 'user.name', 'Donkey Giraffe')
system('git', 'config', 'user.email', 'donkey@giraffe.example.com')
end
end
context 'default remote' do
context 'remote does not exist' do
it 'raises' do
expect { subject }.to raise_error(
Nanoc::Deploying::Deployers::Git::Errors::RemoteDoesNotExist,
'The remote to deploy to, origin, does not exist.',
)
end
end
context 'remote exists' do
before do
Dir.chdir(output_dir) do
system('git', 'remote', 'add', 'origin', '../rere')
end
end
let(:remote) { 'origin' }
include_examples 'remote configured properly'
end
end
context 'custom remote (name)' do
let(:remote_options) { { remote: 'donkey' } }
context 'remote does not exist' do
it 'raises' do
expect { subject }.to raise_error(
Nanoc::Deploying::Deployers::Git::Errors::RemoteDoesNotExist,
'The remote to deploy to, donkey, does not exist.',
)
end
end
context 'remote exists' do
before do
Dir.chdir(output_dir) do
system('git', 'remote', 'add', 'donkey', '../rere')
end
end
let(:remote) { 'donkey' }
include_examples 'remote configured properly'
end
end
context 'custom remote (file:// URL)' do
let(:remote_options) { { remote: remote } }
let(:remote) { "file://#{Dir.getwd}/rere" }
include_examples 'remote configured properly'
end
end
end
describe '#remote_is_name?' do
def val(remote)
deployer.send(:remote_is_name?, remote)
end
it 'recognises names' do
expect(val('denis')).to be
end
it 'recognises URLs' do
expect(val('git@github.com:/foo')).not_to be
expect(val('http://example.com/donkey.git')).not_to be
expect(val('https://example.com/donkey.git')).not_to be
expect(val('ssh://example.com/donkey.git')).not_to be
expect(val('file:///example.com/donkey.git')).not_to be
end
end
end
nanoc-4.11.0/nanoc/spec/nanoc/filters/000077500000000000000000000000001340050175000174645ustar00rootroot00000000000000nanoc-4.11.0/nanoc/spec/nanoc/filters/asciidoc_spec.rb000066400000000000000000000004431340050175000226020ustar00rootroot00000000000000# frozen_string_literal: true
describe Nanoc::Filters::AsciiDoc do
before do
skip_unless_have_command 'asciidoc'
end
subject { described_class.new }
example do
expect(subject.setup_and_run('== Blah blah'))
.to match(%r{Blah blah
})
end
end
nanoc-4.11.0/nanoc/spec/nanoc/filters/asciidoctor_spec.rb000066400000000000000000000004441340050175000233300ustar00rootroot00000000000000# frozen_string_literal: true
describe Nanoc::Filters::Asciidoctor do
subject { filter.setup_and_run(input, params) }
let(:filter) { described_class.new }
let(:input) { '== Blah blah' }
let(:params) { {} }
it { is_expected.to match(%r{Blah blah
}) }
end
nanoc-4.11.0/nanoc/spec/nanoc/filters/colorize_syntax/000077500000000000000000000000001340050175000227205ustar00rootroot00000000000000nanoc-4.11.0/nanoc/spec/nanoc/filters/colorize_syntax/rouge_spec.rb000066400000000000000000000111501340050175000253760ustar00rootroot00000000000000# frozen_string_literal: true
require 'rouge'
describe Nanoc::Filters::ColorizeSyntax, filter: true do
subject { filter.setup_and_run(input, default_colorizer: :rouge, rouge: params) }
let(:filter) { ::Nanoc::Filters::ColorizeSyntax.new }
let(:params) { {} }
let(:wrap) { false }
let(:css_class) { 'highlight' }
let(:input) do
<<~EOS
before
def foo
end
after
EOS
end
let(:output) do
<<~EOS
before
def foo
end
after
EOS
end
context 'with Rouge' do
context 'with default options' do
it { is_expected.to eql output }
end
context 'with legacy' do
let(:legacy) { true }
let(:params) { super().merge(legacy: legacy) }
it { is_expected.to eql output }
context 'with pygments wrapper' do
let(:wrap) { true }
let(:params) { super().merge(wrap: wrap) }
it { is_expected.to eql output }
context 'with css_class' do
let(:css_class) { 'nanoc' }
let(:params) { super().merge(css_class: css_class) }
it { is_expected.to eql output }
end
end
context 'with line number' do
let(:line_numbers) { true }
let(:params) { super().merge(line_numbers: line_numbers) }
let(:output) do
<<~EOS
before
1
2
def foo
end
after
EOS
end
it { is_expected.to eql output }
end
end
context 'with formater' do
let(:params) { super().merge(formatter: formatter) }
context 'with inline' do
let(:formatter) { Rouge::Formatters::HTMLInline.new(theme) }
context 'with github theme' do
let(:theme) { Rouge::Themes::Github.new }
let(:output) do
<<~EOS
before
def foo
end
after
EOS
end
it { is_expected.to eql output }
end
context 'with colorful theme' do
let(:theme) { Rouge::Themes::Colorful.new }
let(:output) do
<<~EOS
before
def foo
end
after
EOS
end
it { is_expected.to eql output }
end
end
context 'with linewise' do
let(:formatter) { Rouge::Formatters::HTMLLinewise.new(Rouge::Formatters::HTML.new) }
let(:output) do
<<~EOS
before
def foo
end
after
EOS
end
it { is_expected.to eql output }
end
context 'with pygments' do
let(:wrap) { true }
let(:css_class) { 'codehilite' }
let(:formatter) { Rouge::Formatters::HTMLPygments.new(Rouge::Formatters::HTML.new) }
it { is_expected.to eql output }
end
context 'with table' do
let(:formatter) { Rouge::Formatters::HTMLTable.new(Rouge::Formatters::HTML.new) }
let(:output) do
<<~EOS
before
1
2
def foo
end
after
EOS
end
it { is_expected.to eql output }
end
end
end
end
nanoc-4.11.0/nanoc/spec/nanoc/filters/erb_spec.rb000066400000000000000000000103511340050175000215730ustar00rootroot00000000000000# frozen_string_literal: true
describe Nanoc::Filters::ERB do
context 'no assigns' do
let(:filter) { described_class.new }
example do
result = filter.setup_and_run('[<%= @foo %>]')
expect(result).to eq('[]')
end
end
context 'simple assigns' do
let(:filter) { described_class.new(location: 'a cheap motel') }
it 'can access assign through instance variable' do
result = filter.setup_and_run(
'<%= "I was hiding in #{@location}." %>', # rubocop:disable Lint/InterpolationCheck
)
expect(result).to eq('I was hiding in a cheap motel.')
end
it 'can access assign through instance method' do
result = filter.setup_and_run(
'<%= "I was hiding in #{location}." %>', # rubocop:disable Lint/InterpolationCheck
)
expect(result).to eq('I was hiding in a cheap motel.')
end
it 'does not accept yield' do
expect { filter.setup_and_run('<%= yield %>') }
.to raise_error(LocalJumpError)
end
end
context 'content assigns' do
let(:filter) { described_class.new(content: 'a cheap motel') }
it 'can access assign through instance variable' do
result = filter.setup_and_run(
'<%= "I was hiding in #{@content}." %>', # rubocop:disable Lint/InterpolationCheck
)
expect(result).to eq('I was hiding in a cheap motel.')
end
it 'can access assign through instance method' do
result = filter.setup_and_run(
'<%= "I was hiding in #{content}." %>', # rubocop:disable Lint/InterpolationCheck
)
expect(result).to eq('I was hiding in a cheap motel.')
end
it 'can access assign through yield' do
result = filter.setup_and_run(
'<%= "I was hiding in #{yield}." %>', # rubocop:disable Lint/InterpolationCheck
)
expect(result).to eq('I was hiding in a cheap motel.')
end
end
context 'locals' do
let(:filter) { described_class.new }
let(:params) { { locals: { location: 'a cheap motel' } } }
it 'can access assign through instance variable' do
result = filter.setup_and_run(
'<%= "I was hiding in #{@location}." %>', # rubocop:disable Lint/InterpolationCheck
params,
)
expect(result).to eq('I was hiding in a cheap motel.')
end
it 'can access assign through instance method' do
result = filter.setup_and_run(
'<%= "I was hiding in #{location}." %>', # rubocop:disable Lint/InterpolationCheck
params,
)
expect(result).to eq('I was hiding in a cheap motel.')
end
end
context 'error' do
let(:filter) { described_class.new(layout: layout) }
let(:layout) { Nanoc::Int::Layout.new('asdf', {}, '/default.erb') }
subject do
filter.setup_and_run('<% raise "boom %>')
end
example do
error =
begin
subject
rescue SyntaxError => e
e
end
expect(error.message).to start_with('layout /default.erb:1: unterminated string meets end of file')
end
end
context 'with trim mode' do
let(:filter) { described_class.new }
let(:res) { { success: false } }
subject do
filter.setup_and_run('% res[:success] = true', params)
end
context 'trim mode unchanged' do
let(:params) do
{
locals: { res: res },
}
end
it 'honors trim mode' do
expect { subject }.not_to change { res[:success] }
end
end
context 'trim mode set' do
let(:params) do
{
trim_mode: '%',
locals: { res: res },
}
end
it 'honors trim mode' do
expect { subject }.to change { res[:success] }.from(false).to(true)
end
end
end
context 'safe level' do
let(:filter) { described_class.new }
let(:res) { { success: false } }
subject do
filter.setup_and_run('<%= eval File.read("moo") %>', params)
end
before do
File.write('moo', '1+2')
end
context 'safe level unchanged' do
let(:params) { {} }
it 'honors safe level' do
expect(subject).to eq('3')
end
end
context 'safe level set' do
let(:params) { { safe_level: 1 } }
it 'honors safe level' do
expect { subject }.to raise_error(SecurityError)
end
end
end
end
nanoc-4.11.0/nanoc/spec/nanoc/filters/less_spec.rb000066400000000000000000000070621340050175000217760ustar00rootroot00000000000000# frozen_string_literal: true
describe Nanoc::Filters::Less, site: true, stdio: true do
# These tests are high-level in order to interact well with the compiler. This is important for
# this :less filter, because of the way it handles fibers.
before do
skip_unless_gem_available('less')
end
before do
File.open('Rules', 'w') do |io|
io.write "compile '/**/*.less' do\n"
io.write " filter :less\n"
io.write " write item.identifier.without_ext + '.css'\n"
io.write "end\n"
end
end
context 'one file' do
let(:content_a) { 'p { color: red; }' }
before do
File.write('content/a.less', content_a)
end
it 'compiles a.less' do
Nanoc::CLI.run(%w[compile])
expect(File.read('output/a.css')).to match(/^p\s*\{\s*color:\s*red;?\s*\}/)
end
context 'with compression' do
let(:content_a) { '.foo { bar: a; } .bar { foo: b; }' }
before do
File.open('Rules', 'w') do |io|
io.write "compile '/*.less' do\n"
io.write " filter :less, compress: true\n"
io.write " write item.identifier.without_ext + '.css'\n"
io.write "end\n"
end
end
it 'compiles and compresses a.less' do
Nanoc::CLI.run(%w[compile])
expect(File.read('output/a.css')).to match(/^\.foo\{bar:a\}\n?\.bar\{foo:b\}/)
end
end
end
context 'two files' do
let(:content_a) { '@import "b.less";' }
let(:content_b) { 'p { color: red; }' }
before do
File.write('content/a.less', content_a)
File.write('content/b.less', content_b)
end
it 'compiles a.less' do
Nanoc::CLI.run(%w[compile])
expect(File.read('output/a.css')).to match(/^p\s*\{\s*color:\s*red;?\s*\}/)
end
it 'recompiles a.less if b.less has changed' do
Nanoc::CLI.run(%w[compile])
File.write('content/b.less', 'p { color: blue; }')
Nanoc::CLI.run(%w[compile])
expect(File.read('output/a.css')).to match(/^p\s*\{\s*color:\s*blue;?\s*\}/)
end
end
context 'paths relative to site directory' do
let(:content_a) { '@import "content/foo/bar/imported_file.less";' }
let(:content_b) { 'p { color: red; }' }
before do
FileUtils.mkdir_p('content/foo/bar')
File.write('content/a.less', content_a)
File.write('content/foo/bar/imported_file.less', content_b)
end
it 'compiles a.less' do
Nanoc::CLI.run(%w[compile])
expect(File.read('output/a.css')).to match(/^p\s*\{\s*color:\s*red;?\s*\}/)
end
it 'recompiles a.less if b.less has changed' do
Nanoc::CLI.run(%w[compile])
File.write('content/foo/bar/imported_file.less', 'p { color: blue; }')
Nanoc::CLI.run(%w[compile])
expect(File.read('output/a.css')).to match(/^p\s*\{\s*color:\s*blue;?\s*\}/)
end
end
context 'paths relative to current file' do
let(:content_a) { '@import "bar/imported_file.less";' }
let(:content_b) { 'p { color: red; }' }
before do
FileUtils.mkdir_p('content/foo/bar')
File.write('content/foo/a.less', content_a)
File.write('content/foo/bar/imported_file.less', content_b)
end
it 'compiles a.less' do
Nanoc::CLI.run(%w[compile])
expect(File.read('output/foo/a.css')).to match(/^p\s*\{\s*color:\s*red;?\s*\}/)
end
it 'recompiles a.less if b.less has changed' do
Nanoc::CLI.run(%w[compile])
File.write('content/foo/bar/imported_file.less', 'p { color: blue; }')
Nanoc::CLI.run(%w[compile])
expect(File.read('output/foo/a.css')).to match(/^p\s*\{\s*color:\s*blue;?\s*\}/)
end
end
end
nanoc-4.11.0/nanoc/spec/nanoc/filters/relativize_paths_spec.rb000066400000000000000000000127261340050175000244100ustar00rootroot00000000000000# frozen_string_literal: true
describe Nanoc::Filters::RelativizePaths do
subject(:filter) { described_class.new(assigns) }
let(:assigns) do
{ item_rep: item_rep }
end
let(:item) do
Nanoc::Int::Item.new('contentz', {}, '/sub/page.html')
end
let(:item_rep) do
Nanoc::Int::ItemRep.new(item, :default).tap do |rep|
rep.paths = { last: ['/sub/page.html'] }
end
end
describe '#run' do
subject { filter.setup_and_run(content, params) }
let(:content) do
'Foo'
end
let(:params) do
{}
end
context 'HTML' do
let(:params) { { type: :html } }
it { is_expected.to eq('Foo') }
context 'full component excluded' do
let(:params) { { type: :html, exclude: '/foo' } }
it { is_expected.to eq('Foo') }
end
context 'full component excluded as list' do
let(:params) { { type: :html, exclude: ['/foo'] } }
it { is_expected.to eq('Foo') }
end
context 'partial component excluded' do
let(:params) { { type: :html, exclude: ['/fo'] } }
it { is_expected.to eq('Foo') }
end
context 'non-root component excluded' do
let(:params) { { type: :html, exclude: ['/bar'] } }
it { is_expected.to eq('Foo') }
end
context 'excluded with regexp' do
let(:params) { { type: :html, exclude: /ar/ } }
it { is_expected.to eq('Foo') }
end
context 'excluded with regexp list' do
let(:params) { { type: :html, exclude: [/ar/] } }
it { is_expected.to eq('Foo') }
end
end
context 'HTML5' do
let(:params) { { type: :html5 } }
it { is_expected.to eq('Foo') }
context 'full component excluded' do
let(:params) { { type: :html5, exclude: '/foo' } }
it { is_expected.to eq('Foo') }
end
context 'full component excluded as list' do
let(:params) { { type: :html5, exclude: ['/foo'] } }
it { is_expected.to eq('Foo') }
end
context 'partial component excluded' do
let(:params) { { type: :html5, exclude: ['/fo'] } }
it { is_expected.to eq('Foo') }
end
context 'non-root component excluded' do
let(:params) { { type: :html5, exclude: ['/bar'] } }
it { is_expected.to eq('Foo') }
end
context 'excluded with regexp' do
let(:params) { { type: :html5, exclude: /ar/ } }
it { is_expected.to eq('Foo') }
end
context 'excluded with regexp list' do
let(:params) { { type: :html5, exclude: [/ar/] } }
it { is_expected.to eq('Foo') }
end
end
context 'XHTML' do
let(:params) { { type: :xhtml } }
it { is_expected.to eq('Foo') }
context 'full component excluded' do
let(:params) { { type: :xhtml, exclude: '/foo' } }
it { is_expected.to eq('Foo') }
end
context 'full component excluded as list' do
let(:params) { { type: :xhtml, exclude: ['/foo'] } }
it { is_expected.to eq('Foo') }
end
context 'partial component excluded' do
let(:params) { { type: :xhtml, exclude: ['/fo'] } }
it { is_expected.to eq('Foo') }
end
context 'non-root component excluded' do
let(:params) { { type: :xhtml, exclude: ['/bar'] } }
it { is_expected.to eq('Foo') }
end
context 'excluded with regexp' do
let(:params) { { type: :xhtml, exclude: /ar/ } }
it { is_expected.to eq('Foo') }
end
context 'excluded with regexp list' do
let(:params) { { type: :xhtml, exclude: [/ar/] } }
it { is_expected.to eq('Foo') }
end
end
context 'CSS' do
let(:params) { { type: :css } }
let(:content) do
'.oink { background: url(/foo/bar.png) }'
end
it { is_expected.to eq('.oink { background: url(../foo/bar.png) }') }
context 'full component excluded' do
let(:params) { { type: :css, exclude: '/foo' } }
it { is_expected.to eq('.oink { background: url(/foo/bar.png) }') }
end
context 'full component excluded as list' do
let(:params) { { type: :css, exclude: ['/foo'] } }
it { is_expected.to eq('.oink { background: url(/foo/bar.png) }') }
end
context 'partial component excluded' do
let(:params) { { type: :css, exclude: ['/fo'] } }
it { is_expected.to eq('.oink { background: url(../foo/bar.png) }') }
end
context 'non-root component excluded' do
let(:params) { { type: :css, exclude: ['/bar'] } }
it { is_expected.to eq('.oink { background: url(../foo/bar.png) }') }
end
context 'excluded with regexp' do
let(:params) { { type: :css, exclude: /ar/ } }
it { is_expected.to eq('.oink { background: url(/foo/bar.png) }') }
end
context 'excluded with regexp list' do
let(:params) { { type: :css, exclude: [/ar/] } }
it { is_expected.to eq('.oink { background: url(/foo/bar.png) }') }
end
end
end
end
nanoc-4.11.0/nanoc/spec/nanoc/filters/sass_spec.rb000066400000000000000000000262261340050175000220040ustar00rootroot00000000000000# frozen_string_literal: true
describe Nanoc::Filters::SassCommon do
context 'with item, items, config context' do
subject(:sass) { ::Nanoc::Filter.named(:sass).new(sass_params) }
subject(:sass_sourcemap) { ::Nanoc::Filter.named(:sass_sourcemap).new(sass_sourcemap_params) }
let(:sass_params) do
{
item: item_main_view,
item_rep: item_main_default_rep_view,
items: item_views,
config: config,
}
end
let(:sass_sourcemap_params) do
{
item: item_main_view,
item_rep: item_main_sourcemap_rep_view,
items: item_views,
config: config,
}
end
let(:item_main) do
Nanoc::Int::Item.new(
content_main,
{ content_filename: 'content/style/main.sass' },
'/style/main.sass',
)
end
let(:content_main) do
Nanoc::Int::TextualContent.new(
'/* irrelevant */',
filename: File.expand_path('content/style/main.sass'),
)
end
let(:item_blue) do
Nanoc::Int::Item.new(
content_blue,
{ content_filename: 'content/style/colors/blue.sass' },
'/style/colors/blue.sass',
)
end
let(:content_blue) do
Nanoc::Int::TextualContent.new(
"\.blue\n color: blue",
filename: File.expand_path('content/style/colors/blue.sass'),
)
end
let(:item_red) do
Nanoc::Int::Item.new(
content_red,
{ content_filename: 'content/style/colors/red.scss' },
'/style/colors/red.scss',
)
end
let(:content_red) do
Nanoc::Int::TextualContent.new(
'.red { color: red; }',
filename: File.expand_path('content/style/colors/red.scss'),
)
end
let(:item_partial) do
Nanoc::Int::Item.new(
content_partial,
{ content_filename: 'content/style/_partial.scss' },
'/style/_partial.scss',
)
end
let(:content_partial) do
Nanoc::Int::TextualContent.new(
'* { margin: 0; }',
filename: File.expand_path('content/style/_partial.scss'),
)
end
let(:item_main_default_rep) do
Nanoc::Int::ItemRep.new(item_main, :default).tap do |rep|
rep.raw_paths = rep.paths = { last: [Dir.getwd + '/output/style/main.sass'] }
end
end
let(:item_main_sourcemap_rep) do
Nanoc::Int::ItemRep.new(item_main, :sourcemap).tap do |rep|
rep.raw_paths = rep.paths = { last: [Dir.getwd + '/output/style/main.sass.map'] }
end
end
let(:item_main_view) { Nanoc::CompilationItemView.new(item_main, view_context) }
let(:item_main_default_rep_view) { Nanoc::CompilationItemRepView.new(item_main_default_rep, view_context) }
let(:item_main_sourcemap_rep_view) { Nanoc::CompilationItemRepView.new(item_main_sourcemap_rep, view_context) }
let(:items) { Nanoc::Int::ItemCollection.new(config, [item_main, item_blue, item_red, item_partial]) }
let(:item_views) { Nanoc::ItemCollectionWithRepsView.new(items, view_context) }
let(:view_context) do
Nanoc::ViewContextForCompilation.new(
reps: reps,
items: items,
dependency_tracker: dependency_tracker,
compilation_context: compilation_context,
snapshot_repo: snapshot_repo,
)
end
let(:reps) do
Nanoc::Int::ItemRepRepo.new.tap do |reps|
[item_blue, item_red, item_partial].each do |item|
reps << Nanoc::Int::ItemRep.new(item, :default).tap do |rep|
rep.compiled = true
rep.snapshot_defs = [Nanoc::Int::SnapshotDef.new(:last, binary: false)]
end
end
reps << item_main_default_rep
reps << item_main_sourcemap_rep
end
end
let(:dependency_tracker) { Nanoc::Int::DependencyTracker.new(dependency_store) }
let(:dependency_store) { Nanoc::Int::DependencyStore.new(empty_items, empty_layouts, config) }
let(:compilation_context) { double(:compilation_context) }
let(:snapshot_repo) do
Nanoc::Int::SnapshotRepo.new.tap do |repo|
repo.set(reps[item_blue].first, :last, Nanoc::Int::TextualContent.new('.blue { color: blue }'))
repo.set(reps[item_red].first, :last, Nanoc::Int::TextualContent.new('.red { color: red }'))
repo.set(reps[item_partial].first, :last, Nanoc::Int::TextualContent.new('* { margin: 0 }'))
end
end
let(:empty_items) { Nanoc::Int::ItemCollection.new(config) }
let(:empty_layouts) { Nanoc::Int::LayoutCollection.new(config) }
let(:config) { Nanoc::Int::Configuration.new(dir: Dir.getwd).with_defaults.merge(color: 'yellow') }
before do
items.each do |item|
FileUtils.mkdir_p(File.dirname(item.attributes[:content_filename]))
File.write(item.attributes[:content_filename], item.content)
end
end
it 'can be called with content' do
expect(sass.setup_and_run(".foo #bar\n color: #f00"))
.to match(/.foo\s+#bar\s*\{\s*color:\s+(red|#f00);?\s*\}/)
end
it 'compacts when using style=compact' do
expect(sass.setup_and_run(".foo #bar\n color: #f00", style: 'compact'))
.to match(/^\.foo #bar[\s]*\{[\s]*color:\s*(red|#f00);?[\s]*\}/m)
end
it 'compacts when using style=compressed' do
expect(sass.setup_and_run(".foo #bar\n color: #f00", style: 'compressed'))
.to match(/^\.foo #bar[\s]*\{[\s]*color:\s*(red|#f00);?[\s]*\}/m)
end
it 'supports SCSS' do
expect(sass.setup_and_run('.foo { color: #f00 }', syntax: :scss))
.to match(/^\.foo[\s]*\{[\s]*color:\s*(red|#f00);?[\s]*\}/m)
end
it 'raises proper error on failure' do
expect { sass.setup_and_run('$*#&!@($') }
.to raise_error(::Sass::SyntaxError, /Invalid variable/)
end
context 'importing a file for which an item exists' do
it 'can import by relative path' do
expect(sass.setup_and_run('@import colors/blue'))
.to match(/\A\.blue\s+\{\s*color:\s+blue;?\s*\}\s*\z/)
expect(sass.setup_and_run('@import colors/red'))
.to match(/\A\.red\s+\{\s*color:\s+red;?\s*\}\s*\z/)
end
it 'cannot import by nested relative path' do
expect { sass.setup_and_run('@import content/style/colors/blue') }
.to raise_error(::Sass::SyntaxError, /File to import not found/)
expect { sass.setup_and_run('@import content/style/colors/red') }
.to raise_error(::Sass::SyntaxError, /File to import not found/)
end
it 'can import by relative path with extension' do
expect(sass.setup_and_run('@import colors/blue.sass'))
.to match(/\A\.blue\s+\{\s*color:\s+blue;?\s*\}\s*\z/)
expect(sass.setup_and_run('@import colors/red.scss'))
.to match(/\A\.red\s+\{\s*color:\s+red;?\s*\}\s*\z/)
end
it 'cannot import by nested relative path with extension' do
expect { sass.setup_and_run('@import content/style/colors/blue.sass') }
.to raise_error(::Sass::SyntaxError, /File to import not found/)
expect { sass.setup_and_run('@import content/style/colors/red.scss') }
.to raise_error(::Sass::SyntaxError, /File to import not found/)
end
it 'can import partials by relative path' do
expect(sass.setup_and_run('@import partial'))
.to match(/\A\*\s*\{\s*margin:\s+0;\s*\}\s*\z/)
end
it 'cannot import partials by nested relative path' do
expect { sass.setup_and_run('@import content/style/_partial') }
.to raise_error(::Sass::SyntaxError, /File to import not found/)
end
it 'can import partials by relative path with extension' do
expect(sass.setup_and_run('@import partial.scss'))
.to match(/\A\*\s*\{\s*margin:\s+0;\s*\}\s*\z/)
end
it 'cannot import partials by nested relative path with extension' do
expect { sass.setup_and_run('@import content/style/partial.scss') }
.to raise_error(::Sass::SyntaxError, /File to import not found/)
end
it 'creates a dependency' do
expect { sass.setup_and_run('@import partial') }
.to create_dependency_on(item_views[item_partial.identifier])
end
end
context 'importing a file for which an item does not exist' do
before { File.write('_external.scss', 'body { font: 100%; }') }
context 'load_path set' do
it 'can import (using load paths) by relative path' do
expect(sass.setup_and_run('@import external', load_paths: ['.']))
.to match(/\Abody\s+\{\s*font:\s+100%;?\s*\}\s*\z/)
end
it 'creates no dependency' do
expect { sass.setup_and_run('@import external', load_paths: ['.']) }
.to create_dependency_from(item_main_view).onto([instance_of(Nanoc::Int::ItemCollection)])
end
end
context 'load_path not set' do
it 'cannot import (using load paths) by relative path' do
expect { sass.setup_and_run('@import external') }
.to raise_error(::Sass::SyntaxError, /File to import not found/)
end
it 'can import (using importer) by relative path' do
expect(sass.setup_and_run('@import "../../_external"'))
.to match(/\Abody\s+\{\s*font:\s+100%;?\s*\}\s*\z/)
end
end
end
context 'importing by identifier or pattern' do
it 'can import by identifier' do
expect(sass.setup_and_run('@import /style/colors/blue.*'))
.to match(/\A\.blue\s+\{\s*color:\s+blue;?\s*\}\s*\z/)
expect(sass.setup_and_run('@import /style/colors/red.*'))
.to match(/\A\.red\s+\{\s*color:\s+red;?\s*\}\s*\z/)
end
it 'can import by pattern' do
expect(sass.setup_and_run('@import /style/colors/*'))
.to match(/\A\.blue\s+\{\s*color:\s+blue;?\s*\}\s*\.red\s+\{\s*color:\s+red;?\s*\}\s*\z/)
end
end
context 'sourcemaps' do
it 'generates proper sourcemaps' do
expect(sass.setup_and_run(".foo #bar\n color: #f00", sourcemap_path: 'main.css.map'))
.to match(/.foo\s+#bar\s*\{\s*color:\s+(red|#f00);?\s*\}\s*\/\*# sourceMappingURL=main.css.map \*\//)
expect(sass_sourcemap.setup_and_run(".foo #bar\n color: #f00", css_path: 'main.css', sourcemap_path: 'main.css.map'))
.to match(/{.*?"sources": \["#{item_main_default_rep.raw_path}"\].*?"file": "main\.css".*?}/m)
expect(sass_sourcemap.setup_and_run(".foo #bar\n color: #f00", sourcemap_path: 'main.css.map'))
.not_to match(/{.*?"sources": \["#{item_main_default_rep.raw_path}"\].*?"file": ".*?".*?}/m)
end
it 'generates inlined sourcemaps' do
expect(sass.setup_and_run(".foo #bar\n color: #f00", css_path: 'main.css', sourcemap_path: :inline))
.to match(/.foo\s+#bar\s*\{\s*color:\s+(red|#f00);?\s*\}\s*\/\*# sourceMappingURL=data:application\/json;base64.*? \*\//)
end
end
context 'nanoc() sass function' do
it 'can inspect @config' do
expect(sass.setup_and_run(".foo #bar\n color: nanoc('@config[:color]', $unquote: true)"))
.to match(/.foo\s+#bar\s*\{\s*color:\s+yellow;?\s*\}/)
end
it 'can inspect @items' do
expect(sass.setup_and_run(".foo\n content: nanoc('@items[\"/style/main.*\"][:content_filename]')"))
.to match(/.foo\s*\{\s*content:\s+"content\/style\/main\.sass";?\s*\}/)
end
end
end
end
nanoc-4.11.0/nanoc/spec/nanoc/helpers/000077500000000000000000000000001340050175000174565ustar00rootroot00000000000000nanoc-4.11.0/nanoc/spec/nanoc/helpers/blogging_spec.rb000066400000000000000000000135321340050175000226110ustar00rootroot00000000000000# frozen_string_literal: true
describe Nanoc::Helpers::Blogging, helper: true do
before do
allow(ctx.dependency_tracker).to receive(:enter)
allow(ctx.dependency_tracker).to receive(:exit)
end
describe '#articles' do
subject { helper.articles }
before do
ctx.create_item('blah', { kind: 'item' }, '/0')
ctx.create_item('blah blah', { kind: 'article' }, '/1')
ctx.create_item('blah blah blah', { kind: 'article' }, '/2')
end
it 'returns the two articles' do
expect(subject.map(&:identifier)).to match_array(['/1', '/2'])
end
end
describe '#sorted_articles' do
subject { helper.sorted_articles }
before do
attrs = { kind: 'item' }
ctx.create_item('blah', attrs, '/0')
attrs = { kind: 'article', created_at: (Date.today - 1).to_s }
ctx.create_item('blah blah', attrs, '/1')
attrs = { kind: 'article', created_at: (Time.now - 500).to_s }
ctx.create_item('blah blah blah', attrs, '/2')
end
it 'returns the two articles in descending order' do
expect(subject.map(&:identifier)).to eq(['/2', '/1'])
end
end
describe '#url_for' do
subject { helper.url_for(ctx.items['/stuff']) }
let(:item_attributes) { {} }
before do
ctx.create_item('Stuff', item_attributes, '/stuff')
ctx.create_rep(ctx.items['/stuff'], '/rep/path/stuff.html')
ctx.config[:base_url] = base_url
end
context 'without base_url' do
let(:base_url) { nil }
it 'raises' do
expect { subject }.to raise_error(Nanoc::Error)
end
end
context 'with base_url' do
let(:base_url) { 'http://url.base' }
context 'with custom_url_in_feed' do
let(:item_attributes) do
{ custom_url_in_feed: 'http://example.com/stuff.html' }
end
it 'returns custom URL' do
expect(subject).to eql('http://example.com/stuff.html')
end
end
context 'without custom_url_in_feed' do
context 'with custom_path_in_feed' do
let(:item_attributes) do
{ custom_path_in_feed: '/stuff.html' }
end
it 'returns base URL + custom path' do
expect(subject).to eql('http://url.base/stuff.html')
end
end
context 'without custom_path_in_feed' do
it 'returns base URL + path' do
expect(subject).to eql('http://url.base/rep/path/stuff.html')
end
end
end
end
end
describe '#feed_url' do
subject { helper.feed_url }
let(:item_attributes) { {} }
before do
ctx.create_item('Feed', item_attributes, '/feed')
ctx.create_rep(ctx.items['/feed'], '/feed.xml')
ctx.item = ctx.items['/feed']
ctx.config[:base_url] = base_url
end
context 'without base_url' do
let(:base_url) { nil }
it 'raises' do
expect { subject }.to raise_error(Nanoc::Error)
end
end
context 'with base_url' do
let(:base_url) { 'http://url.base' }
context 'with feed_url' do
let(:item_attributes) do
{ feed_url: 'http://custom.feed.url/feed.rss' }
end
it 'returns custom URL' do
expect(subject).to eql('http://custom.feed.url/feed.rss')
end
end
context 'without feed_url' do
it 'returns base URL + path' do
expect(subject).to eql('http://url.base/feed.xml')
end
end
end
end
describe '#attribute_to_time' do
subject { helper.attribute_to_time(arg) }
let(:noon_s) { 1_446_903_076 }
let(:beginning_of_day_s) { 1_446_854_400 }
let(:around_noon_local) { Time.at(noon_s - Time.at(noon_s).utc_offset) }
let(:around_noon_utc) { Time.at(noon_s) }
let(:beginning_of_day_utc) { Time.at(beginning_of_day_s) }
context 'with Time instance' do
let(:arg) { around_noon_utc }
it { is_expected.to eql(around_noon_utc) }
end
context 'with Date instance' do
let(:arg) { Date.new(2015, 11, 7) }
it { is_expected.to eql(beginning_of_day_utc) }
end
context 'with DateTime instance' do
let(:arg) { DateTime.new(2015, 11, 7, 13, 31, 16) } # rubocop:disable Style/DateTime
it { is_expected.to eql(around_noon_utc) }
end
context 'with string' do
let(:arg) { '2015-11-7 13:31:16' }
it { is_expected.to eql(around_noon_local) }
end
end
describe '#atom_tag_for' do
subject { helper.atom_tag_for(ctx.items['/stuff']) }
let(:item_attributes) { { created_at: '2015-05-19 12:34:56' } }
let(:item_rep_path) { '/stuff.xml' }
let(:base_url) { 'http://url.base' }
before do
ctx.create_item('Stuff', item_attributes, '/stuff')
ctx.create_rep(ctx.items['/stuff'], item_rep_path)
ctx.config[:base_url] = base_url
end
context 'item with path' do
let(:item_rep_path) { '/stuff.xml' }
it { is_expected.to eql('tag:url.base,2015-05-19:/stuff.xml') }
end
context 'item without path' do
let(:item_rep_path) { nil }
it { is_expected.to eql('tag:url.base,2015-05-19:/stuff') }
end
context 'bare URL without subdir' do
let(:base_url) { 'http://url.base' }
it { is_expected.to eql('tag:url.base,2015-05-19:/stuff.xml') }
end
context 'bare URL with subdir' do
let(:base_url) { 'http://url.base/sub' }
it { is_expected.to eql('tag:url.base,2015-05-19:/sub/stuff.xml') }
end
context 'created_at is date' do
let(:item_attributes) do
{ created_at: Date.parse('2015-05-19 12:34:56') }
end
it { is_expected.to eql('tag:url.base,2015-05-19:/stuff.xml') }
end
context 'created_at is time' do
let(:item_attributes) do
{ created_at: Time.parse('2015-05-19 12:34:56') }
end
it { is_expected.to eql('tag:url.base,2015-05-19:/stuff.xml') }
end
# TODO: handle missing base_dir
# TODO: handle missing created_at
end
end
nanoc-4.11.0/nanoc/spec/nanoc/helpers/breadcrumbs_spec.rb000066400000000000000000000211521340050175000233070ustar00rootroot00000000000000# frozen_string_literal: true
describe Nanoc::Helpers::Breadcrumbs, helper: true, stdio: true do
before do
allow(ctx.dependency_tracker).to receive(:enter)
allow(ctx.dependency_tracker).to receive(:exit)
end
describe '#breadcrumbs_trail' do
subject { helper.breadcrumbs_trail }
context 'legacy identifiers' do
context 'root' do
before do
ctx.create_item('root', {}, Nanoc::Identifier.new('/', type: :legacy))
ctx.item = ctx.items['/']
end
it 'returns an array with the item' do
expect(subject).to eql([ctx.items['/']])
end
end
context 'root and direct child' do
before do
ctx.create_item('child', {}, Nanoc::Identifier.new('/foo/', type: :legacy))
ctx.create_item('root', {}, Nanoc::Identifier.new('/', type: :legacy))
ctx.item = ctx.items['/foo/']
end
it 'returns an array with the items' do
expect(subject).to eql([ctx.items['/'], ctx.items['/foo/']])
end
end
context 'root, child and grandchild' do
before do
ctx.create_item('grandchild', {}, Nanoc::Identifier.new('/foo/bar/', type: :legacy))
ctx.create_item('child', {}, Nanoc::Identifier.new('/foo/', type: :legacy))
ctx.create_item('root', {}, Nanoc::Identifier.new('/', type: :legacy))
ctx.item = ctx.items['/foo/bar/']
end
it 'returns an array with the items' do
expect(subject).to eql([ctx.items['/'], ctx.items['/foo/'], ctx.items['/foo/bar/']])
end
end
context 'root, missing child and grandchild' do
before do
ctx.create_item('grandchild', {}, Nanoc::Identifier.new('/foo/bar/', type: :legacy))
ctx.create_item('root', {}, Nanoc::Identifier.new('/', type: :legacy))
ctx.item = ctx.items['/foo/bar/']
end
it 'returns an array with the items' do
expect(subject).to eql([ctx.items['/'], nil, ctx.items['/foo/bar/']])
end
end
end
context 'non-legacy identifiers' do
context 'root' do
before do
ctx.create_item('root', {}, Nanoc::Identifier.new('/index.md'))
ctx.item = ctx.items['/index.md']
end
it 'returns an array with the item' do
expect(subject).to eql([ctx.items['/index.md']])
end
end
context 'root and direct child' do
before do
ctx.create_item('child', {}, Nanoc::Identifier.new('/foo.md'))
ctx.create_item('root', {}, Nanoc::Identifier.new('/index.md'))
ctx.item = ctx.items['/foo.md']
end
it 'returns an array with the items' do
expect(subject).to eql([ctx.items['/index.md'], ctx.items['/foo.md']])
end
end
context 'root, child and grandchild' do
before do
ctx.create_item('grandchild', {}, Nanoc::Identifier.new('/foo/bar.md'))
ctx.create_item('child', {}, Nanoc::Identifier.new('/foo.md'))
ctx.create_item('root', {}, Nanoc::Identifier.new('/index.md'))
ctx.item = ctx.items['/foo/bar.md']
end
it 'returns an array with the items' do
expect(subject).to eql([ctx.items['/index.md'], ctx.items['/foo.md'], ctx.items['/foo/bar.md']])
end
end
context 'root, missing child and grandchild' do
before do
ctx.create_item('grandchild', {}, Nanoc::Identifier.new('/foo/bar.md'))
ctx.create_item('root', {}, Nanoc::Identifier.new('/index.md'))
ctx.item = ctx.items['/foo/bar.md']
end
it 'returns an array with the items' do
expect(subject).to eql([ctx.items['/index.md'], nil, ctx.items['/foo/bar.md']])
end
end
context 'index.md child' do
# No special handling of non-root index.* files.
before do
ctx.create_item('grandchild', {}, Nanoc::Identifier.new('/foo/index.md'))
ctx.create_item('root', {}, Nanoc::Identifier.new('/index.md'))
ctx.item = ctx.items['/foo/index.md']
end
it 'returns an array with the items' do
expect(subject).to eql([ctx.items['/index.md'], nil, ctx.items['/foo/index.md']])
end
end
context 'item with version number component in path' do
before do
ctx.create_item('grandchild', {}, Nanoc::Identifier.new('/1.5/stuff.md'))
ctx.create_item('child0', {}, Nanoc::Identifier.new('/1.4.md'))
ctx.create_item('child1', {}, Nanoc::Identifier.new('/1.5.md'))
ctx.create_item('child2', {}, Nanoc::Identifier.new('/1.6.md'))
ctx.create_item('root', {}, Nanoc::Identifier.new('/index.md'))
ctx.item = ctx.items['/1.5/stuff.md']
end
it 'picks the closest parent' do
expect(subject)
.to eql(
[
ctx.items['/index.md'],
ctx.items['/1.5.md'],
ctx.items['/1.5/stuff.md'],
],
)
end
end
context 'item with multiple extensions in path' do
before do
ctx.create_item('grandchild', {}, Nanoc::Identifier.new('/foo/stuff.md'))
ctx.create_item('child0', {}, Nanoc::Identifier.new('/foo.md.erb'))
ctx.create_item('child1', {}, Nanoc::Identifier.new('/foo.md'))
ctx.create_item('child2', {}, Nanoc::Identifier.new('/foo.erb'))
ctx.create_item('root', {}, Nanoc::Identifier.new('/index.md'))
ctx.item = ctx.items['/foo/stuff.md']
end
context 'no tiebreaker specified' do
it 'picks the first' do
expect(subject)
.to eql(
[
ctx.items['/index.md'],
ctx.items['/foo.erb'],
ctx.items['/foo/stuff.md'],
],
)
end
it 'logs a warning' do
expect { subject }.to output(Regexp.new(Regexp.escape('Warning: The breadcrumbs trail (generated by #breadcrumbs_trail) found more than one potential parent item at /foo.* (found /foo.erb, /foo.md, /foo.md.erb). Nanoc will pick the first item as the parent. Consider eliminating the ambiguity by making only one item match /foo.*, or by passing a `:tiebreaker` option to `#breadcrumbs_trail`. (This situation will be an error in the next major version of Nanoc.)'))).to_stderr
end
end
context 'tiebreaker :error specified' do
subject { helper.breadcrumbs_trail(tiebreaker: :error) }
it 'errors because of ambiguity' do
expect { subject }
.to raise_error(
Nanoc::Helpers::Breadcrumbs::AmbiguousAncestorError,
'expected only one item to match /foo.*, but found 3',
)
end
end
context 'tiebreaker which picks the last' do
subject { helper.breadcrumbs_trail(tiebreaker: tiebreaker) }
let(:tiebreaker) do
->(items, _pattern) { items.max_by(&:identifier) }
end
it 'picks the last' do
expect(subject)
.to eql(
[
ctx.items['/index.md'],
ctx.items['/foo.md.erb'],
ctx.items['/foo/stuff.md'],
],
)
end
end
context 'tiebreaker without pattern arg which picks the last' do
subject { helper.breadcrumbs_trail(tiebreaker: tiebreaker) }
let(:tiebreaker) do
->(items) { items.max_by(&:identifier) }
end
it 'picks the last' do
expect(subject)
.to eql(
[
ctx.items['/index.md'],
ctx.items['/foo.md.erb'],
ctx.items['/foo/stuff.md'],
],
)
end
end
end
context 'child with multiple extensions' do
before do
ctx.create_item('grandchild1', {}, Nanoc::Identifier.new('/foo/stuff.zip'))
ctx.create_item('grandchild2', {}, Nanoc::Identifier.new('/foo/stuff.md'))
ctx.create_item('grandchild3', {}, Nanoc::Identifier.new('/foo/stuff.png'))
ctx.create_item('child', {}, Nanoc::Identifier.new('/foo.md'))
ctx.create_item('root', {}, Nanoc::Identifier.new('/index.md'))
ctx.item = ctx.items['/foo/stuff.md']
end
it 'picks the best parent' do
expect(subject)
.to eql(
[
ctx.items['/index.md'],
ctx.items['/foo.md'],
ctx.items['/foo/stuff.md'],
],
)
end
end
end
end
end
nanoc-4.11.0/nanoc/spec/nanoc/helpers/capturing_spec.rb000066400000000000000000000173701340050175000230210ustar00rootroot00000000000000# frozen_string_literal: true
describe Nanoc::Helpers::Capturing, helper: true do
describe '#content_for' do
before do
ctx.create_item('some content', {}, '/about.md')
ctx.create_rep(ctx.items['/about.md'], '/about.html')
ctx.item = ctx.items['/about.md']
end
describe 'setting content' do
let(:_erbout) { +'existing content' }
let(:params) { raise 'overwrite me' }
let(:contents_enumerator) { %w[foo bar].to_enum }
shared_examples 'setting content' do
context 'only name given' do
subject { subject_proc_without_params.call }
it 'stores snapshot content' do
subject
expect(ctx.snapshot_repo.get(ctx.item.reps[:default]._unwrap, :__capture_foo).string).to eql('foo')
end
end
context 'name and params given' do
subject { subject_proc_with_params.call }
let(:params) { raise 'overwrite me' }
context 'no existing behavior specified' do
let(:params) { {} }
it 'errors after two times' do
subject_proc_with_params.call
expect { subject_proc_with_params.call }.to raise_error(RuntimeError)
end
end
context 'existing behavior is :overwrite' do
let(:params) { { existing: :overwrite } }
it 'overwrites' do
subject_proc_with_params.call
subject_proc_with_params.call
expect(ctx.snapshot_repo.get(ctx.item.reps[:default]._unwrap, :__capture_foo).string).to eql('bar')
end
end
context 'existing behavior is :append' do
let(:params) { { existing: :append } }
it 'appends' do
subject_proc_with_params.call
subject_proc_with_params.call
expect(ctx.snapshot_repo.get(ctx.item.reps[:default]._unwrap, :__capture_foo).string).to eql('foobar')
end
end
context 'existing behavior is :error' do
let(:params) { { existing: :error } }
it 'errors after two times' do
subject_proc_with_params.call
expect { subject_proc_with_params.call }.to raise_error(RuntimeError)
end
end
context 'existing behavior is :something else' do
let(:params) { { existing: :donkey } }
it 'errors' do
expect { subject }.to raise_error(ArgumentError)
end
end
end
end
context 'symbol name + block' do
let(:subject_proc_without_params) do
-> { helper.content_for(:foo) { _erbout << contents_enumerator.next } }
end
let(:subject_proc_with_params) do
-> { helper.content_for(:foo, params) { _erbout << contents_enumerator.next } }
end
include_examples 'setting content'
end
context 'string name + block' do
let(:subject_proc_without_params) do
-> { helper.content_for('foo') { _erbout << contents_enumerator.next } }
end
let(:subject_proc_with_params) do
-> { helper.content_for('foo', params) { _erbout << contents_enumerator.next } }
end
include_examples 'setting content'
end
context 'symbol name + string' do
let(:subject_proc_without_params) do
-> { helper.content_for(:foo, contents_enumerator.next) }
end
let(:subject_proc_with_params) do
-> { helper.content_for(:foo, params, contents_enumerator.next) }
end
include_examples 'setting content'
end
context 'string name + string' do
let(:subject_proc_without_params) do
-> { helper.content_for('foo', contents_enumerator.next) }
end
let(:subject_proc_with_params) do
-> { helper.content_for('foo', params, contents_enumerator.next) }
end
include_examples 'setting content'
end
end
describe 'with item + name' do
subject { helper.content_for(item, :foo) }
let(:_erbout) { +'existing content' }
context 'requesting for same item' do
let(:item) { ctx.item }
context 'nothing captured' do
it { is_expected.to be_nil }
end
context 'something captured' do
before do
helper.content_for(:foo) { _erbout << 'I have been captured!' }
end
it { is_expected.to eql('I have been captured!') }
end
end
context 'requesting for other item' do
let(:item) { ctx.items['/other.md'] }
before do
ctx.create_item('other content', {}, '/other.md')
ctx.create_rep(ctx.items['/other.md'], '/other.html')
end
context 'other item is not yet compiled' do
it 'raises an unmet dependency error' do
expect(ctx.dependency_tracker).to receive(:bounce).with(item._unwrap, compiled_content: true)
expect { subject }.to raise_error(FiberError)
end
it 're-runs when fiber is resumed' do
expect(ctx.dependency_tracker).to receive(:bounce).with(item._unwrap, compiled_content: true).twice
fiber = Fiber.new { subject }
expect(fiber.resume).to be_a(Nanoc::Int::Errors::UnmetDependency)
item.reps[:default]._unwrap.compiled = true
ctx.snapshot_repo.set(
item.reps[:default]._unwrap,
:__capture_foo,
Nanoc::Int::TextualContent.new('content after compilation'),
)
expect(fiber.resume).to eql('content after compilation')
end
end
context 'other item is compiled' do
before do
item.reps[:default]._unwrap.compiled = true
ctx.snapshot_repo.set(
item.reps[:default]._unwrap,
:__capture_foo,
Nanoc::Int::TextualContent.new('other captured foo'),
)
end
it 'returns the captured content' do
expect(ctx.dependency_tracker).to receive(:bounce).with(item._unwrap, compiled_content: true)
expect(subject).to eql('other captured foo')
end
end
end
end
end
describe '#capture' do
context 'with string' do
let(:_erbout) { +'existing content' }
subject { helper.capture { _erbout << 'new content' } }
it 'returns the appended content' do
expect(subject).to eql('new content')
end
it 'does not modify _erbout' do
expect { subject }.not_to change { _erbout }
end
end
context 'with array' do
let(:_erbout) { ['existing content'] }
shared_examples 'returns properly joined output' do
subject { helper.capture { _erbout << %w[new _ content] } }
it 'returns the appended content, joined' do
expect(subject).to eql('new_content')
end
it 'does not modify _erbout' do
expect { subject }.not_to change { _erbout.join('') }
end
end
context 'default output field separator' do
include_examples 'returns properly joined output'
end
context 'output field separator set to ,' do
around do |ex|
orig_output_field_separator = $OUTPUT_FIELD_SEPARATOR
$OUTPUT_FIELD_SEPARATOR = ','
ex.run
$OUTPUT_FIELD_SEPARATOR = orig_output_field_separator
end
include_examples 'returns properly joined output'
end
context 'output field separator set to nothing' do
around do |ex|
orig_output_field_separator = $OUTPUT_FIELD_SEPARATOR
$OUTPUT_FIELD_SEPARATOR = +''
ex.run
$OUTPUT_FIELD_SEPARATOR = orig_output_field_separator
end
include_examples 'returns properly joined output'
end
end
end
end
nanoc-4.11.0/nanoc/spec/nanoc/helpers/child_parent_spec.rb000066400000000000000000000052221340050175000234520ustar00rootroot00000000000000# frozen_string_literal: true
describe Nanoc::Helpers::ChildParent, helper: true do
describe '#children_of' do
subject { helper.children_of(item) }
before { ctx.create_item('some content', {}, identifier) }
let(:item) { ctx.items[identifier] }
context 'legacy identifier' do
let(:identifier) { Nanoc::Identifier.new('/foo/', type: :legacy) }
before do
ctx.create_item('abc', {}, Nanoc::Identifier.new('/foo/a/', type: :legacy))
ctx.create_item('def', {}, Nanoc::Identifier.new('/foo/a/b/', type: :legacy))
ctx.create_item('xyz', {}, Nanoc::Identifier.new('/bar/', type: :legacy))
end
it 'returns only direct children' do
expect(subject).to eql([ctx.items['/foo/a/']])
end
end
context 'full identifier' do
let(:identifier) { Nanoc::Identifier.new('/foo.md', type: :full) }
before do
ctx.create_item('abc', {}, Nanoc::Identifier.new('/foo/a.md', type: :full))
ctx.create_item('def', {}, Nanoc::Identifier.new('/foo/a/b.md', type: :full))
ctx.create_item('xyz', {}, Nanoc::Identifier.new('/bar.md', type: :full))
ctx.create_item('xyz', {}, Nanoc::Identifier.new('/foo/a/index.md', type: :full))
end
it 'returns only direct children' do
expect(subject).to eql([ctx.items['/foo/a.md']])
end
end
end
describe '#parent_of' do
subject { helper.parent_of(item) }
before { ctx.create_item('some content', {}, identifier) }
let(:item) { ctx.items[identifier] }
context 'legacy identifier' do
let(:identifier) { Nanoc::Identifier.new('/foo/bar/', type: :legacy) }
before do
ctx.create_item('abc', {}, Nanoc::Identifier.new('/foo/', type: :legacy))
ctx.create_item('def', {}, Nanoc::Identifier.new('/foo/qux/', type: :legacy))
ctx.create_item('xyz', {}, Nanoc::Identifier.new('/foo/bar/asdf/', type: :legacy))
ctx.create_item('opq', {}, Nanoc::Identifier.new('/', type: :legacy))
end
it 'returns parent' do
expect(subject).to eql(ctx.items['/foo/'])
end
end
context 'full identifier' do
let(:identifier) { Nanoc::Identifier.new('/foo/bar.md', type: :full) }
before do
ctx.create_item('abc', {}, Nanoc::Identifier.new('/foo.md', type: :full))
ctx.create_item('def', {}, Nanoc::Identifier.new('/foo/qux.md', type: :full))
ctx.create_item('xyz', {}, Nanoc::Identifier.new('/foo/bar/asdf.md', type: :full))
ctx.create_item('opq', {}, Nanoc::Identifier.new('/index.md', type: :full))
end
it 'returns parent' do
expect(subject).to eql(ctx.items['/foo.md'])
end
end
end
end
nanoc-4.11.0/nanoc/spec/nanoc/helpers/filtering_spec.rb000066400000000000000000000036031340050175000230020ustar00rootroot00000000000000# frozen_string_literal: true
describe Nanoc::Helpers::Filtering, helper: true do
describe '#filter' do
before do
ctx.create_item('some content', { title: 'Hello!' }, '/about.md')
ctx.create_rep(ctx.items['/about.md'], '/about.html')
ctx.item = ctx.items['/about.md']
ctx.item_rep = ctx.item.reps[:default]
end
let(:content) do
"A<% filter :erb do %><%%= 'X' %><% end %>B"
end
subject { ::ERB.new(content).result(helper.get_binding) }
context 'basic case' do
it { is_expected.to eql('AXB') }
it 'notifies' do
ns = Set.new
Nanoc::Int::NotificationCenter.on(:filtering_started) { ns << :filtering_started }
Nanoc::Int::NotificationCenter.on(:filtering_ended) { ns << :filtering_ended }
subject
expect(ns).to include(:filtering_started)
expect(ns).to include(:filtering_ended)
end
end
context 'with assigns' do
let(:content) do
'A<% filter :erb do %><%%= @item[:title] %><% end %>B'
end
it { is_expected.to eql('AHello!B') }
end
context 'unknonwn filter name' do
let(:content) do
'A<% filter :donkey do %>X<% end %>B'
end
it 'errors' do
expect { subject }.to raise_error(Nanoc::Int::Errors::UnknownFilter)
end
end
context 'with locals' do
let(:content) do
"A<% filter :erb, locals: { sheep: 'baah' } do %><%%= @sheep %><% end %>B"
end
it { is_expected.to eql('AbaahB') }
end
context 'with Haml' do
let(:content) do
"%p Foo.\n" \
"- filter(:erb) do\n" \
" <%= 'abc' + 'xyz' %>\n" \
"%p Bar.\n"
end
before do
require 'haml'
end
subject { ::Haml::Engine.new(content).render(helper.get_binding) }
it { is_expected.to match(%r{^Foo.
\s*abcxyz\s*Bar.
$}) }
end
end
end
nanoc-4.11.0/nanoc/spec/nanoc/helpers/html_escape_spec.rb000066400000000000000000000016451340050175000233070ustar00rootroot00000000000000# frozen_string_literal: true
describe Nanoc::Helpers::HTMLEscape, helper: true do
describe '#html_escape' do
subject { helper.html_escape(string) }
context 'given strings to escape' do
let(:string) { '< > & "' }
it { is_expected.to eql('< > & "') }
end
context 'given a block' do
let!(:_erbout) { +'moo' }
it 'adds escaped content to _erbout' do
helper.html_escape { _erbout << 'Stuff!
' }
expect(_erbout).to eql('moo<h1>Stuff!</h1>')
end
end
context 'given no argument nor block' do
subject { helper.html_escape }
it 'raises' do
expect { subject }.to raise_error(RuntimeError)
end
end
context 'given argument that is not a string' do
let(:string) { 1 }
it 'raises an ArgumentError' do
expect { subject }.to raise_error(ArgumentError)
end
end
end
end
nanoc-4.11.0/nanoc/spec/nanoc/helpers/link_to_spec.rb000066400000000000000000000207711340050175000224630ustar00rootroot00000000000000# frozen_string_literal: true
describe Nanoc::Helpers::LinkTo, helper: true do
describe '#link_to' do
subject { helper.link_to(text, target, attributes) }
let(:text) { 'Text' }
let(:target) { raise 'override me' }
let(:attributes) { {} }
context 'with string path' do
let(:target) { '/foo/' }
it { is_expected.to eql('Text') }
context 'with attributes' do
let(:attributes) { { title: 'Donkey' } }
it { is_expected.to eql('Text') }
end
context 'special HTML characters in text' do
let(:text) { 'Foo & Bar' }
it { is_expected.to eql('Foo & Bar') }
# Not escaped!
end
context 'special HTML characters in URL' do
let(:target) { '/r&d/' }
it { is_expected.to eql('Text') }
end
context 'special HTML characters in attribute' do
let(:attributes) { { title: 'Research & Development' } }
it { is_expected.to eql('Text') }
end
end
context 'with rep' do
before do
ctx.create_item('content', {}, '/target')
ctx.create_rep(ctx.items['/target'], '/target.html')
end
let(:target) { ctx.items['/target'].reps[:default] }
it { is_expected.to eql('Text') }
end
context 'with item' do
before do
ctx.create_item('content', {}, '/target')
end
let(:target) { ctx.items['/target'] }
before do
ctx.create_rep(target, '/target.html')
end
it { is_expected.to eql('Text') }
end
context 'with nil' do
let(:target) { nil }
it 'raises' do
expect { subject }.to raise_error(ArgumentError)
end
end
context 'with something else' do
let(:target) { :donkey }
it 'raises' do
expect { subject }.to raise_error(ArgumentError)
end
end
context 'with nil path' do
before do
ctx.create_item('content', {}, '/target')
ctx.create_rep(ctx.items['/target'], nil)
end
let(:target) { ctx.items['/target'].reps[:default] }
it 'raises' do
expect { subject }.to raise_error(RuntimeError)
end
end
end
describe '#link_to_unless_current' do
subject { helper.link_to_unless_current(text, target, attributes) }
let(:text) { 'Text' }
let(:target) { raise 'override me' }
let(:attributes) { {} }
context 'with string path' do
let(:target) { '/target.html' }
context 'current' do
before do
ctx.create_item('content', {}, '/target.md')
ctx.create_rep(ctx.items['/target.md'], '/target.html')
ctx.item = ctx.items['/target.md']
ctx.item_rep = ctx.item.reps[:default]
end
it { is_expected.to eql('Text') }
end
context 'no item rep present' do
it { is_expected.to eql('Text') }
end
context 'item rep present, but not current' do
before do
ctx.create_item('content', {}, '/other.md')
ctx.create_rep(ctx.items['/other.md'], '/other.html')
ctx.item = ctx.items['/other.md']
ctx.item_rep = ctx.item.reps[:default]
end
it { is_expected.to eql('Text') }
end
end
context 'with rep' do
before do
ctx.create_item('content', {}, '/target.md')
ctx.create_rep(ctx.items['/target.md'], '/target.html')
ctx.create_item('content', {}, '/other.md')
ctx.create_rep(ctx.items['/other.md'], '/other.html')
ctx.item = ctx.items['/target.md']
ctx.item_rep = ctx.item.reps[:default]
end
let(:some_item) { ctx.items['/other.md'] }
let(:some_item_rep) { some_item.reps[:default] }
context 'current' do
let(:target) { ctx.item_rep }
it { is_expected.to eql('Text') }
end
context 'no item rep present' do
let(:target) { some_item_rep }
before do
ctx.item = nil
ctx.item_rep = nil
end
it { is_expected.to eql('Text') }
end
context 'item rep present, but not current' do
let(:target) { some_item_rep }
it { is_expected.to eql('Text') }
end
end
context 'with item' do
before do
ctx.create_item('content', {}, '/target.md')
ctx.create_rep(ctx.items['/target.md'], '/target.html')
ctx.create_item('content', {}, '/other.md')
ctx.create_rep(ctx.items['/other.md'], '/other.html')
ctx.item = ctx.items['/target.md']
ctx.item_rep = ctx.item.reps[:default]
end
let(:some_item) { ctx.items['/other.md'] }
let(:some_item_rep) { some_item.reps[:default] }
context 'current' do
let(:target) { ctx.item }
it { is_expected.to eql('Text') }
end
context 'no item rep present' do
let(:target) { some_item }
before do
ctx.item = nil
ctx.item_rep = nil
end
it { is_expected.to eql('Text') }
end
context 'item rep present, but not current' do
let(:target) { some_item }
it { is_expected.to eql('Text') }
end
end
end
describe '#relative_path_to' do
subject { helper.relative_path_to(target) }
before do
ctx.create_item('content', {}, '/foo/self.md')
ctx.create_rep(ctx.items['/foo/self.md'], self_path)
ctx.item = ctx.items['/foo/self.md']
ctx.item_rep = ctx.item.reps[:default]
end
context 'current item rep has non-nil path' do
let(:self_path) { '/foo/self.html' }
context 'to string path' do
context 'to relative path' do
let(:target) { 'bar/target.html' }
it 'errors' do
# TODO: Might make sense to allow this case (and return the path itself)
expect { subject }.to raise_error(ArgumentError)
end
end
context 'to path without trailing slash' do
let(:target) { '/bar/target.html' }
it { is_expected.to eql('../bar/target.html') }
end
context 'to path with trailing slash' do
let(:target) { '/bar/target/' }
it { is_expected.to eql('../bar/target/') }
end
context 'to Windows/UNC path (forward slashes)' do
let(:target) { '//foo' }
it { is_expected.to eql('//foo') }
end
context 'to Windows/UNC path (backslashes)' do
let(:target) { '\\\\foo' }
it { is_expected.to eql('\\\\foo') }
end
end
context 'to rep' do
before do
ctx.create_rep(ctx.item, '/bar/target.html', :special)
end
let(:target) { ctx.item.reps[:special] }
it { is_expected.to eql('../bar/target.html') }
context 'to self' do
let(:target) { ctx.item_rep }
context 'self is a filename' do
it { is_expected.to eql('self.html') }
end
context 'self is a directory' do
let(:self_path) { '/foo/self/' }
it { is_expected.to eql('./') }
end
end
end
context 'to item' do
let(:target) { ctx.items['/bar/target.md'] }
before do
ctx.create_item('content', {}, '/bar/target.md')
ctx.create_rep(ctx.items['/bar/target.md'], '/bar/target.html')
end
it { is_expected.to eql('../bar/target.html') }
context 'to self' do
let(:target) { ctx.item }
context 'self is a filename' do
it { is_expected.to eql('self.html') }
end
context 'self is a directory' do
let(:self_path) { '/foo/self/' }
it { is_expected.to eql('./') }
end
end
end
context 'to nil path' do
let(:target) { ctx.item.reps[:special] }
before do
ctx.create_rep(ctx.item, nil, :special)
end
it 'raises' do
expect { subject }.to raise_error(RuntimeError)
end
end
end
context 'current item rep has nil path' do
let(:self_path) { nil }
let(:target) { '/bar/target.html' }
it 'errors' do
expect { subject }.to raise_error(RuntimeError)
end
end
end
end
nanoc-4.11.0/nanoc/spec/nanoc/helpers/rendering_spec.rb000066400000000000000000000104701340050175000227740ustar00rootroot00000000000000# frozen_string_literal: true
describe Nanoc::Helpers::Rendering, helper: true do
describe '#render' do
subject { helper.instance_eval { render('/partial.erb') } }
let(:action_sequence_for_layout) do
[Nanoc::Int::ProcessingActions::Filter.new(:erb, {})]
end
let(:layout_view) { ctx.layouts[layout_identifier] }
let(:layout) { layout_view._unwrap }
before do
ctx.create_layout(layout_content, {}, layout_identifier)
ctx.update_action_sequence(layout, action_sequence_for_layout)
end
context 'legacy identifier' do
let(:layout_identifier) { Nanoc::Identifier.new('/partial/', type: :legacy) }
context 'cleaned identifier' do
subject { helper.instance_eval { render('/partial/') } }
context 'layout without instructions' do
let(:layout_content) { 'blah' }
it { is_expected.to eql('blah') }
it 'tracks proper dependencies' do
expect(ctx.dependency_tracker).to receive(:enter)
.with(an_instance_of(Nanoc::Int::LayoutCollection), raw_content: ['/partial/'], attributes: false, compiled_content: false, path: false)
.ordered
expect(ctx.dependency_tracker).to receive(:enter)
.with(layout, raw_content: true, attributes: false, compiled_content: false, path: false)
.ordered
subject
end
end
context 'layout with instructions' do
let(:layout_content) { 'blah <%= @layout.identifier %>' }
it { is_expected.to eql('blah /partial/') }
end
end
context 'non-cleaned identifier' do
subject { helper.instance_eval { render('/partial') } }
context 'layout without instructions' do
let(:layout_content) { 'blah' }
it { is_expected.to eql('blah') }
end
context 'layout with instructions' do
let(:layout_content) { 'blah <%= @layout.identifier %>' }
it { is_expected.to eql('blah /partial/') }
end
end
end
context 'full-style identifier' do
let(:layout_identifier) { Nanoc::Identifier.new('/partial.erb') }
context 'layout without instructions' do
let(:layout_content) { 'blah' }
it { is_expected.to eql('blah') }
end
context 'layout with instructions' do
let(:layout_content) { 'blah <%= @layout.identifier %>' }
it { is_expected.to eql('blah /partial.erb') }
end
context 'printing wrapped layout class' do
let(:layout_content) { 'blah <%= @layout.class %>' }
it { is_expected.to eql('blah Nanoc::LayoutView') }
end
context 'printing unwrapped layout class' do
let(:layout_content) { 'blah <%= @layout._unwrap.class %>' }
it { is_expected.to eql('blah Nanoc::Int::Layout') }
end
context 'unknown layout' do
subject { helper.instance_eval { render('/unknown.erb') } }
let(:layout_content) { 'blah' }
it 'raises' do
expect { subject }.to raise_error(Nanoc::Int::Errors::UnknownLayout)
end
end
context 'layout with unknown filter' do
let(:action_sequence_for_layout) do
[Nanoc::Int::ProcessingActions::Filter.new(:donkey, {})]
end
let(:layout_content) { 'blah' }
it 'raises' do
expect { subject }.to raise_error(Nanoc::Int::Errors::UnknownFilter)
end
end
context 'layout without filter' do
let(:action_sequence_for_layout) do
[Nanoc::Int::ProcessingActions::Filter.new(nil, {})]
end
let(:layout_content) { 'blah' }
it 'raises' do
expect { subject }.to raise_error(Nanoc::Int::Errors::CannotDetermineFilter)
end
end
context 'with block' do
subject do
helper.instance_eval do
render('/partial.erb') { _erbout << 'extra content' }
end
end
before do
ctx.erbout << '[erbout-before]'
end
let(:layout_content) { '[partial-before]<%= yield %>[partial-after]' }
it 'returns an empty string' do
expect(subject).to eql('')
end
it 'modifies erbout' do
subject
expect(ctx.erbout).to eql('[erbout-before][partial-before]extra content[partial-after]')
end
end
end
end
end
nanoc-4.11.0/nanoc/spec/nanoc/helpers/tagging_spec.rb000066400000000000000000000060171340050175000224410ustar00rootroot00000000000000# frozen_string_literal: true
describe Nanoc::Helpers::Tagging, helper: true do
describe '#tags_for' do
subject { helper.tags_for(item, params) }
let(:item) { ctx.items['/me.*'] }
let(:params) { {} }
let(:item_attributes) { {} }
before do
ctx.create_item('content', item_attributes, '/me.md')
end
context 'no tags' do
let(:item_attributes) { {} }
it { is_expected.to eql('(none)') }
end
context 'nil tag list' do
let(:item_attributes) { { tags: nil } }
it { is_expected.to eql('(none)') }
end
context 'empty tag list' do
let(:item_attributes) { { tags: [] } }
it { is_expected.to eql('(none)') }
end
context 'no tags, and custom none text' do
let(:item_attributes) { {} }
let(:params) { { none_text: 'no tags for you, fool' } }
it { is_expected.to eql('no tags for you, fool') }
end
context 'one tag' do
let(:item_attributes) { { tags: %w[donkey] } }
context 'implicit base_url' do
it { is_expected.to eql('donkey') }
end
context 'explicit nil base_url' do
let(:params) { { base_url: nil } }
it { is_expected.to eql('donkey') }
end
context 'explicit other base_url' do
let(:params) { { base_url: 'http://nanoc.ws/tag/' } }
it { is_expected.to eql('donkey') }
end
end
context 'two tags' do
let(:item_attributes) { { tags: %w[donkey giraffe] } }
it { is_expected.to eql('donkey, giraffe') }
end
context 'three tags' do
let(:item_attributes) { { tags: %w[donkey giraffe zebra] } }
it { is_expected.to eql('donkey, giraffe, zebra') }
context 'custom separator' do
let(:item_attributes) { { tags: %w[donkey giraffe zebra] } }
let(:params) { { separator: ' / ' } }
it { is_expected.to eql('donkey / giraffe / zebra') }
end
end
end
describe '#items_with_tag' do
subject { helper.items_with_tag(tag) }
before do
ctx.create_item('item 1', { tags: [:foo] }, '/item1.md')
ctx.create_item('item 2', { tags: [:bar] }, '/item2.md')
ctx.create_item('item 3', { tags: %i[foo bar] }, '/item3.md')
ctx.create_item('item 4', { tags: nil }, '/item4.md')
ctx.create_item('item 5', {}, '/item5.md')
end
context 'tag that exists' do
let(:tag) { :foo }
it { is_expected.to contain_exactly(ctx.items['/item1.md'], ctx.items['/item3.md']) }
end
context 'tag that does not exists' do
let(:tag) { :other }
it { is_expected.to be_empty }
end
end
describe '#link_for_tag' do
subject { helper.link_for_tag(tag, base_url) }
let(:tag) { 'foo' }
let(:base_url) { 'http://nanoc.ws/tag/' }
it { is_expected.to eql('foo') }
context 'tag with special HTML characters' do
let(:tag) { 'R&D' }
it { is_expected.to eql('R&D') }
end
end
end
nanoc-4.11.0/nanoc/spec/nanoc/helpers/text_spec.rb000066400000000000000000000025361340050175000220070ustar00rootroot00000000000000# frozen_string_literal: true
describe Nanoc::Helpers::Text, helper: true do
describe '#excerptize' do
subject { helper.excerptize(string, params) }
let(:string) { 'Foo bar baz quux meow woof' }
let(:params) { {} }
context 'no params' do
it 'takes 25 characters' do
expect(subject).to eql('Foo bar baz quux meow ...')
end
end
context 'perfect fit' do
let(:params) { { length: 26 } }
it 'does not truncate' do
expect(subject).to eql('Foo bar baz quux meow woof')
end
end
context 'long length' do
let(:params) { { length: 27 } }
it 'does not truncate' do
expect(subject).to eql('Foo bar baz quux meow woof')
end
end
context 'short length' do
let(:params) { { length: 3 } }
it 'truncates' do
expect(subject).to eql('...')
end
end
context 'length shorter than omission' do
let(:params) { { length: 2 } }
it 'truncates, disregarding length' do
expect(subject).to eql('...')
end
end
context 'custom omission' do
let(:params) { { omission: '[continued]' } }
it 'uses custom omission string' do
expect(subject).to eql('Foo bar baz qu[continued]')
end
end
end
describe '#strip_html' do
# TODO: test this… or get rid of it (it’s bad!)
end
end
nanoc-4.11.0/nanoc/spec/nanoc/integration/000077500000000000000000000000001340050175000203375ustar00rootroot00000000000000nanoc-4.11.0/nanoc/spec/nanoc/integration/compile_command_spec.rb000066400000000000000000000033661340050175000250340ustar00rootroot00000000000000# frozen_string_literal: true
describe 'Compile command', site: true, stdio: true do
describe 'diff generation' do
before do
File.write('content/foo.md', "I am foo!\n")
File.write('Rules', <<~EOS)
compile '/foo.*' do
write '/foo.html'
end
EOS
end
it 'does not generate diff by default' do
FileUtils.mkdir_p('output')
File.write('output/foo.html', "I am old foo!\n")
Nanoc::CLI.run(%w[compile])
expect(File.file?('output.diff')).not_to be
end
it 'honors --diff' do
FileUtils.mkdir_p('output')
File.write('output/foo.html', "I am old foo!\n")
Nanoc::CLI.run(%w[compile --diff])
expect(File.file?('output.diff')).to be
end
end
it 'recompiles when changing routes' do
# Create items
File.open('content/a.html', 'w') do |io|
io.write('A
')
end
File.open('content/b.html', 'w') do |io|
io.write('B
')
end
# Create routes
File.open('Rules', 'w') do |io|
io.write "compile '**/*' do\n"
io.write "end\n"
io.write "\n"
io.write "route '/a.*' do\n"
io.write " '/index.html'\n"
io.write "end\n"
end
# Compile
site = Nanoc::Int::SiteLoader.new.new_from_cwd
site.compile
# Check
expect(File.read('output/index.html')).to eq('A
')
# Create routes
File.open('Rules', 'w') do |io|
io.write "compile '**/*' do\n"
io.write "end\n"
io.write "\n"
io.write "route '/b.*' do\n"
io.write " '/index.html'\n"
io.write "end\n"
end
# Compile
site = Nanoc::Int::SiteLoader.new.new_from_cwd
site.compile
# Check
expect(File.read('output/index.html')).to eq('B
')
end
end
nanoc-4.11.0/nanoc/spec/nanoc/integration/outdatedness_integration_spec.rb000066400000000000000000000211421340050175000270030ustar00rootroot00000000000000# frozen_string_literal: true
describe 'Outdatedness integration', site: true, stdio: true do
context 'only attribute dependency' do
let(:time) { Time.now }
before do
File.write('content/foo.md', "---\ntitle: hello\n---\n\nfoo")
File.write('content/bar.md', '<%= @items["/foo.*"][:title] %>')
FileUtils.touch('content/foo.md', mtime: time)
FileUtils.touch('content/bar.md', mtime: time)
File.write('Rules', <<~EOS)
compile '/foo.*' do
write '/foo.html'
end
compile '/bar.*' do
filter :erb
write '/bar.html'
end
EOS
end
before { Nanoc::CLI.run(%w[compile]) }
it 'shows default rep outdatedness' do
expect { Nanoc::CLI.run(%w[show-data --no-color]) }.to(
output(/^item \/foo\.md, rep default:\n is not outdated/).to_stdout,
)
expect { Nanoc::CLI.run(%w[show-data --no-color]) }.to(
output(/^item \/bar\.md, rep default:\n is not outdated/).to_stdout,
)
end
it 'shows file as outdated after modification' do
File.write('content/bar.md', 'JUST BAR!')
FileUtils.touch('content/bar.md', mtime: time)
expect { Nanoc::CLI.run(%w[show-data --no-color]) }.to(
output(/^item \/foo\.md, rep default:\n is not outdated/).to_stdout,
)
expect { Nanoc::CLI.run(%w[show-data --no-color]) }.to(
output(/^item \/bar\.md, rep default:\n is outdated:/).to_stdout,
)
end
it 'shows file and dependencies as not outdated after content modification' do
File.write('content/foo.md', "---\ntitle: hello\n---\n\nfoooOoooOOoooOooo")
FileUtils.touch('content/foo.md', mtime: time)
expect { Nanoc::CLI.run(%w[show-data --no-color]) }.to(
output(/^item \/foo\.md, rep default:\n is outdated:/).to_stdout,
)
expect { Nanoc::CLI.run(%w[show-data --no-color]) }.to(
output(/^item \/bar\.md, rep default:\n is not outdated/).to_stdout,
)
end
it 'shows file and dependencies as outdated after title modification' do
File.write('content/foo.md', "---\ntitle: bye\n---\n\nfoo")
FileUtils.touch('content/foo.md', mtime: time)
expect { Nanoc::CLI.run(%w[show-data --no-color]) }.to(
output(/^item \/foo\.md, rep default:\n is outdated:/).to_stdout,
)
expect { Nanoc::CLI.run(%w[show-data --no-color]) }.to(
output(/^item \/bar\.md, rep default:\n is outdated:/).to_stdout,
)
end
end
context 'only attribute dependency on config' do
let(:time) { Time.now }
before do
File.write('content/bar.md', '<%= @config[:title] %>')
FileUtils.touch('content/bar.md', mtime: time)
File.write('nanoc.yaml', <<~EOS)
title: The Original
EOS
File.write('Rules', <<~EOS)
compile '/foo.*' do
write '/foo.html'
end
compile '/bar.*' do
filter :erb
write '/bar.html'
end
EOS
end
before { Nanoc::CLI.run(%w[compile]) }
it 'shows default rep outdatedness' do
expect { Nanoc::CLI.run(%w[show-data --no-color]) }.to(
output(/^item \/bar\.md, rep default:\n is not outdated/).to_stdout,
)
end
it 'shows file as outdated after modification' do
File.write('content/bar.md', 'JUST BAR!')
FileUtils.touch('content/bar.md', mtime: time)
expect { Nanoc::CLI.run(%w[show-data --no-color]) }.to(
output(/^item \/bar\.md, rep default:\n is outdated:/).to_stdout,
)
end
it 'shows file and dependencies as outdated after title modification' do
File.write('nanoc.yaml', 'title: Totes Newz')
FileUtils.touch('nanoc.yaml', mtime: time)
expect { Nanoc::CLI.run(%w[show-data --no-color]) }.to(
output(/^item \/bar\.md, rep default:\n is outdated:/).to_stdout,
)
end
end
context 'only raw content dependency' do
before do
File.write('content/foo.md', "---\ntitle: hello\n---\n\nfoo")
File.write('content/bar.md', '<%= @items["/foo.*"].raw_content %>')
File.write('Rules', <<~EOS)
compile '/foo.*' do
write '/foo.html'
end
compile '/bar.*' do
filter :erb
write '/bar.html'
end
EOS
end
before { Nanoc::CLI.run(%w[compile]) }
it 'shows default rep outdatedness' do
expect { Nanoc::CLI.run(%w[show-data --no-color]) }.to(
output(/^item \/foo\.md, rep default:\n is not outdated/).to_stdout,
)
expect { Nanoc::CLI.run(%w[show-data --no-color]) }.to(
output(/^item \/bar\.md, rep default:\n is not outdated/).to_stdout,
)
end
it 'shows file as outdated after modification' do
File.write('content/bar.md', 'JUST BAR!')
expect { Nanoc::CLI.run(%w[show-data --no-color]) }.to(
output(/^item \/foo\.md, rep default:\n is not outdated/).to_stdout,
)
expect { Nanoc::CLI.run(%w[show-data --no-color]) }.to(
output(/^item \/bar\.md, rep default:\n is outdated:/).to_stdout,
)
end
it 'shows file and dependencies as outdated after content modification' do
File.write('content/foo.md', "---\ntitle: hello\n---\n\nfoooOoooOOoooOooo")
expect { Nanoc::CLI.run(%w[show-data --no-color]) }.to(
output(/^item \/foo\.md, rep default:\n is outdated:/).to_stdout,
)
expect { Nanoc::CLI.run(%w[show-data --no-color]) }.to(
output(/^item \/bar\.md, rep default:\n is outdated:/).to_stdout,
)
end
it 'shows file and dependencies as not outdated after title modification' do
File.write('content/foo.md', "---\ntitle: bye\n---\n\nfoo")
expect { Nanoc::CLI.run(%w[show-data --no-color]) }.to(
output(/^item \/foo\.md, rep default:\n is outdated:/).to_stdout,
)
expect { Nanoc::CLI.run(%w[show-data --no-color]) }.to(
output(/^item \/bar\.md, rep default:\n is not outdated/).to_stdout,
)
end
end
context 'attribute and raw content dependency' do
before do
File.write('content/foo.md', "---\ntitle: hello\n---\n\nfoo")
File.write('content/bar.md', '<%= @items["/foo.*"].raw_content %> / <%= @items["/foo.*"][:title] %>')
File.write('Rules', <<~EOS)
compile '/foo.*' do
write '/foo.html'
end
compile '/bar.*' do
filter :erb
write '/bar.html'
end
EOS
end
before { Nanoc::CLI.run(%w[compile]) }
it 'shows default rep outdatedness' do
expect { Nanoc::CLI.run(%w[show-data --no-color]) }.to(
output(/^item \/foo\.md, rep default:\n is not outdated/).to_stdout,
)
expect { Nanoc::CLI.run(%w[show-data --no-color]) }.to(
output(/^item \/bar\.md, rep default:\n is not outdated/).to_stdout,
)
end
it 'shows file as outdated after modification' do
File.write('content/bar.md', 'JUST BAR!')
expect { Nanoc::CLI.run(%w[show-data --no-color]) }.to(
output(/^item \/foo\.md, rep default:\n is not outdated/).to_stdout,
)
expect { Nanoc::CLI.run(%w[show-data --no-color]) }.to(
output(/^item \/bar\.md, rep default:\n is outdated:/).to_stdout,
)
end
it 'shows file and dependencies as outdated after content modification' do
File.write('content/foo.md', "---\ntitle: hello\n---\n\nfoooOoooOOoooOooo")
expect { Nanoc::CLI.run(%w[show-data --no-color]) }.to(
output(/^item \/foo\.md, rep default:\n is outdated:/).to_stdout,
)
expect { Nanoc::CLI.run(%w[show-data --no-color]) }.to(
output(/^item \/bar\.md, rep default:\n is outdated:/).to_stdout,
)
end
it 'shows file and dependencies as outdated after title modification' do
File.write('content/foo.md', "---\ntitle: bye\n---\n\nfoo")
expect { Nanoc::CLI.run(%w[show-data --no-color]) }.to(
output(/^item \/foo\.md, rep default:\n is outdated:/).to_stdout,
)
expect { Nanoc::CLI.run(%w[show-data --no-color]) }.to(
output(/^item \/bar\.md, rep default:\n is outdated:/).to_stdout,
)
end
it 'shows file and dependencies as not outdated after rule modification' do
File.write('Rules', <<~EOS)
compile '/foo.*' do
filter :erb
write '/foo.html'
end
compile '/bar.*' do
filter :erb
write '/bar.html'
end
EOS
expect { Nanoc::CLI.run(%w[show-data --no-color]) }.to(
output(/^item \/foo\.md, rep default:\n is outdated:/).to_stdout,
)
expect { Nanoc::CLI.run(%w[show-data --no-color]) }.to(
output(/^item \/bar\.md, rep default:\n is not outdated/).to_stdout,
)
end
end
end
nanoc-4.11.0/nanoc/spec/nanoc/integration/partial_recompilation_spec.rb000066400000000000000000000034051340050175000262610ustar00rootroot00000000000000# frozen_string_literal: true
describe 'Partial recompilation', site: true, stdio: true do
before do
File.write('content/foo.md', "---\ntitle: hello\n---\n\nfoo")
File.write('content/bar.md', '<%= @items["/foo.*"].compiled_content %><% raise "boom" %>')
File.write('Rules', <<~EOS)
compile '/foo.*' do
write '/foo.html'
end
compile '/bar.*' do
filter :erb
write '/bar.html'
end
EOS
end
example do
expect(File.file?('output/foo.html')).not_to be
expect(File.file?('output/bar.html')).not_to be
expect { Nanoc::CLI.run(%w[show-data --no-color]) }
.to(output(/^item \/foo\.md, rep default:\n is outdated:/).to_stdout)
expect { Nanoc::CLI.run(%w[show-data --no-color]) }
.to(output(/^item \/bar\.md, rep default:\n is outdated:/).to_stdout)
expect { Nanoc::CLI.run(%w[compile --verbose]) rescue nil }
.to output(/create.*output\/foo\.html/).to_stdout
expect { Nanoc::CLI.run(%w[show-data --no-color]) }
.to(output(/^item \/foo\.md, rep default:\n is not outdated/).to_stdout)
expect { Nanoc::CLI.run(%w[show-data --no-color]) }
.to(output(/^item \/bar\.md, rep default:\n is outdated:/).to_stdout)
expect(File.file?('output/foo.html')).to be
expect(File.file?('output/bar.html')).not_to be
File.write('content/bar.md', '<% raise "boom" %>')
expect { Nanoc::CLI.run(%w[compile --verbose --debug]) rescue nil }
.to output(/skip.*output\/foo\.html/).to_stdout
expect { Nanoc::CLI.run(%w[show-data --no-color]) }
.to(output(/^item \/foo\.md, rep default:\n is not outdated/).to_stdout)
expect { Nanoc::CLI.run(%w[show-data --no-color]) }
.to(output(/^item \/bar\.md, rep default:\n is outdated:/).to_stdout)
end
end
nanoc-4.11.0/nanoc/spec/nanoc/integration/toml_config_spec.rb000066400000000000000000000010461340050175000241770ustar00rootroot00000000000000# frozen_string_literal: true
describe 'TOML configuration', site: true, stdio: true do
example do
File.write('content/foo.md', '<%= @config[:animal] %>')
File.write('Rules', <<~EOS)
compile '/foo.*' do
filter :erb
write '/foo.html'
end
EOS
FileUtils.rm_f('nanoc.yaml')
File.write('nanoc.toml', <<~EOS)
animal = "donkey"
EOS
Nanoc::Feature.enable(Nanoc::Feature::TOML) do
Nanoc::CLI.run(%w[compile])
end
expect(File.read('output/foo.html')).to eq('donkey')
end
end
nanoc-4.11.0/nanoc/spec/nanoc/integration/write_nil_spec.rb000066400000000000000000000044341340050175000236770ustar00rootroot00000000000000# frozen_string_literal: true
describe 'write nil (skip routing rule)', site: true, stdio: true do
context 'write non-nil + write nil' do
before do
File.write('content/foo.md', 'foo')
File.write('Rules', <<~EOS)
compile '/foo.*' do
write '/foo-via-compilation-rule.txt'
write nil
end
route '/foo.*' do
'/foo-via-routing-rule.txt'
end
EOS
end
it 'starts off empty' do
expect(File.file?('output/foo-via-compilation-rule.txt')).not_to be
expect(File.file?('output/foo-via-routing-rule.txt')).not_to be
end
it 'outputs creation of correct file' do
expect { Nanoc::CLI.run(%w[compile --verbose]) rescue nil }
.to output(/create.*output\/foo-via-compilation-rule\.txt/).to_stdout
end
it 'does not output creation of incorrect file' do
expect { Nanoc::CLI.run(%w[compile --verbose]) rescue nil }
.not_to output(/create.*output\/foo-via-routing-rule\.txt/).to_stdout
end
it 'creates correct file' do
expect { Nanoc::CLI.run(%w[compile --verbose --debug]) rescue nil }
.to change { File.file?('output/foo-via-compilation-rule.txt') }
.from(false)
.to(true)
end
it 'does not create incorrect file' do
expect { Nanoc::CLI.run(%w[compile --verbose --debug]) rescue nil }
.not_to change { File.file?('output/foo-via-routing-rule.txt') }
end
end
context 'write nil only' do
before do
File.write('content/foo.md', 'foo')
File.write('Rules', <<~EOS)
compile '/foo.*' do
write nil
end
route '/foo.*' do
'/foo-via-routing-rule.txt'
end
EOS
end
it 'starts off empty' do
expect(File.file?('output/foo-via-compilation-rule.txt')).not_to be
expect(File.file?('output/foo-via-routing-rule.txt')).not_to be
end
it 'does not output creation of incorrect file' do
expect { Nanoc::CLI.run(%w[compile --verbose]) rescue nil }
.not_to output(/create.*output\/foo-via-routing-rule\.txt/).to_stdout
end
it 'does not create incorrect file' do
expect { Nanoc::CLI.run(%w[compile --verbose --debug]) rescue nil }
.not_to change { File.file?('output/foo-via-routing-rule.txt') }
end
end
end
nanoc-4.11.0/nanoc/spec/nanoc/regressions/000077500000000000000000000000001340050175000203575ustar00rootroot00000000000000nanoc-4.11.0/nanoc/spec/nanoc/regressions/gh_1015_spec.rb000066400000000000000000000007121340050175000227620ustar00rootroot00000000000000# frozen_string_literal: true
describe 'GH-1015', site: true, stdio: true do
before do
File.write('content/foo.md', 'I am foo!')
File.write('Rules', < / <%= yield %>')
File.write('Rules', <]')
File.write('content/bar.md', 'I am bar!')
File.write('Rules', <]')
File.write('content/bar.md', 'I am bar!')
File.write('lib/stuff.rb', <<~EOS)
Class.new(Nanoc::Filter) do
identifier :gh_1031_text2bin
type :text => :binary
def run(content, params = {})
File.write(output_filename, content)
end
end
EOS
File.write('Rules', <]')
File.write('Rules', <')
File.write('content/bar.txt', 'foo=<%= @items["/foo.*"].compiled_content %>')
File.write('layouts/default.erb', '*<%= yield %>*')
File.write('Rules', <')
File.write('nanoc.yaml', <<~EOS)
base_url: 'http://example.com'
EOS
File.write('lib/default.rb', <<~EOS)
include Nanoc::Helpers::XMLSitemap
EOS
File.write('Rules', <<~EOS)
compile '/*.txt' do
write item.identifier.without_ext + '/index.html'
end
compile '/sitemap.erb' do
filter :erb
write item.identifier.without_ext + '.xml'
end
EOS
end
it 'creates the sitemap' do
Nanoc::CLI.run(%w[compile])
expect(File.file?('output/sitemap.xml')).to be
contents = File.read('output/sitemap.xml')
expect(contents).to match(%r{http://example.com/foo/ })
expect(contents).to match(%r{2015-03-02 })
end
it 'updates the sitemap' do
Nanoc::CLI.run(%w[compile])
File.write('content/foo.txt', 'foo 2')
FileUtils.touch('content/foo.txt', mtime: Time.parse('2016-04-03 10:00:00Z'))
Nanoc::CLI.run(%w[compile])
expect(File.file?('output/sitemap.xml')).to be
contents = File.read('output/sitemap.xml')
expect(contents).to match(%r{http://example.com/foo/ })
expect(contents).to match(%r{2016-04-03 })
end
end
nanoc-4.11.0/nanoc/spec/nanoc/regressions/gh_1047_spec.rb000066400000000000000000000020111340050175000227610ustar00rootroot00000000000000# frozen_string_literal: true
describe 'GH-1047', site: true, stdio: true do
before do
File.write('Rules', <<%= raise "boom" %>')
expect { Nanoc::CLI.run(%w[compile]) }.to raise_error(Nanoc::Int::Errors::CompilationError)
expect(File.read('output/foo.md')).to eql('I am foo!')
File.write('content/bar.md', '[<%= @items["/foo.*"].compiled_content %>]')
Nanoc::CLI.run(%w[compile])
expect(File.read('output/foo.md')).to eql('I am foo!')
expect(File.read('output/bar.md')).to eql('[I am foo!]')
end
end
nanoc-4.11.0/nanoc/spec/nanoc/regressions/gh_1064_spec.rb000066400000000000000000000007311340050175000227670ustar00rootroot00000000000000# frozen_string_literal: true
describe 'GH-1064', site: true, stdio: true do
before do
File.write('content/foo.erb', '*<%= @items["/bar.*"].compiled_content(snapshot: :pre) %>*')
File.write('content/bar.erb', 'Bar!')
File.write('Rules', <')
File.write('Rules', <')
File.write('content/b.erb', 'stuff')
File.write('Rules', <')
File.write('content/b.dat', 'stuff')
File.write('Rules', <')
File.write('content/b.erb', '<%= @items["/a.*"].reps[:default].binary? %>')
File.write('Rules', <')
File.write('Rules', <')
File.write('content/z.dat', 'asdf')
File.write('Rules', <')
File.write('Rules', <')
File.write('content/z.dat', 'quux')
File.write('Rules', <')
File.write('Rules', <')
File.write('Rules', <', encoding: 'utf-8')
File.write('lib/asdf.rb', 'EMOJI_🔥 = "hot"', encoding: 'utf-8')
File.write('Rules', <<~EOS)
compile '/**/*' do
filter :erb
write '/last.html'
end
EOS
end
around do |ex|
orig_encoding = Encoding.default_external
Encoding.default_external = 'ASCII'
ex.run
Encoding.default_external = orig_encoding
end
it 'does not crash' do
Nanoc::CLI.run(%w[compile])
expect(File.read('output/last.html')).to eql('hot')
end
end
context 'ISO 8859-1 code UTF-8 env' do
before do
File.write('content/hi.md', '<%= ::BRØKEN %>')
File.write('lib/asdf.rb', "# encoding: iso-8859-1\n\nBRØKEN = 1", encoding: 'ISO-8859-1')
File.write('Rules', <<~EOS)
compile '/**/*' do
filter :erb
write '/last.html'
end
EOS
end
it 'detects manually specified encodings' do
Nanoc::CLI.run(%w[compile])
expect(File.read('output/last.html')).to eql('1')
end
end
end
nanoc-4.11.0/nanoc/spec/nanoc/regressions/gh_1185_spec.rb000066400000000000000000000006331340050175000227740ustar00rootroot00000000000000# frozen_string_literal: true
describe 'GH-1185', site: true, stdio: true do
before do
File.write('content/foo.html', 'stuff')
File.write('Rules', <<~EOS)
preprocess do
@items['/foo.*'].identifier = '/bar.html'
end
compile '/**/*' do
filter :erb
write ext: 'html'
end
EOS
end
it 'does not crash' do
Nanoc::CLI.run(%w[compile])
end
end
nanoc-4.11.0/nanoc/spec/nanoc/regressions/gh_1216_spec.rb000066400000000000000000000043601340050175000227700ustar00rootroot00000000000000# frozen_string_literal: true
describe 'GH-1216', site: true, stdio: true do
before do
FileUtils.mkdir_p('content/talks')
File.write('content/talks/aaa.html', 'A')
File.write('content/talks/bbb.html', 'B')
File.write('content/talks.html', '<%= @items.find_all("/talks/*").map { |i| i.raw_content + "=" + i[:status].to_s }.sort.join(" ") %>')
File.write('Rules', <<~EOS)
compile '/**/*' do
filter :erb
write ext: 'html'
end
EOS
end
before do
Nanoc::CLI.run(%w[compile])
end
context 'attributes changed using #[]=' do
before do
File.write('Rules', <<~EOS)
preprocess do
@items['/talks/aaa.*'][:status] = 'archived'
@items['/talks/bbb.*'][:status] = 'archived'
end
compile '/**/*' do
filter :erb
write ext: 'html'
end
EOS
end
it 'changes output file' do
expect { Nanoc::CLI.run(%w[compile]) }
.to change { File.read('output/talks.html') }
.from('A= B=')
.to('A=archived B=archived')
end
end
context 'attributes changed using update_attributes' do
before do
File.write('Rules', <<~EOS)
preprocess do
@items['/talks/aaa.*'].update_attributes(status: 'archived')
@items['/talks/bbb.*'].update_attributes(status: 'archived')
end
compile '/**/*' do
filter :erb
write ext: 'html'
end
EOS
end
it 'changes output file' do
expect { Nanoc::CLI.run(%w[compile]) }
.to change { File.read('output/talks.html') }
.from('A= B=')
.to('A=archived B=archived')
end
end
context 'raw content changed' do
before do
File.write('Rules', <<~EOS)
preprocess do
@items['/talks/aaa.*'][:status] = 'archived'
@items['/talks/bbb.*'][:status] = 'current'
@items['/talks/aaa.*'].raw_content = 'AAH'
end
compile '/**/*' do
filter :erb
write ext: 'html'
end
EOS
end
it 'changes output file' do
expect { Nanoc::CLI.run(%w[compile]) }
.to change { File.read('output/talks.html') }
.from('A= B=')
.to('AAH=archived B=current')
end
end
end
nanoc-4.11.0/nanoc/spec/nanoc/regressions/gh_1248_spec.rb000066400000000000000000000007311340050175000227730ustar00rootroot00000000000000# frozen_string_literal: true
describe 'GH-1248', site: true, stdio: true do
before do
File.write('content/stuff.html', 'hi')
File.write('Rules', <<~EOS)
preprocess do
@config[:output_dir] = 'ootpoot'
end
passthrough '/**/*'
EOS
end
before do
Nanoc::CLI.run(%w[compile])
end
example do
expect { Nanoc::CLI.run(%w[compile --verbose]) }
.not_to output(/identical .* ootpoot\/stuff.html/).to_stdout
end
end
nanoc-4.11.0/nanoc/spec/nanoc/regressions/gh_1313_spec.rb000066400000000000000000000010451340050175000227630ustar00rootroot00000000000000# frozen_string_literal: true
describe 'GH-1313', site: true, stdio: true do
before do
File.write('nanoc.yaml', <<~CONFIG)
output_dir: build/bin/web/bin
prune:
auto_prune: true
exclude:
- bin
CONFIG
end
before do
FileUtils.mkdir_p('build/bin/web/bin')
File.write('build/bin/web/bin/should-be-pruned', 'asdf')
end
example do
expect { Nanoc::CLI.run(%w[compile]) }
.to change { File.file?('build/bin/web/bin/should-be-pruned') }
.from(true)
.to(false)
end
end
nanoc-4.11.0/nanoc/spec/nanoc/regressions/gh_1319_spec.rb000066400000000000000000000007311340050175000227720ustar00rootroot00000000000000# frozen_string_literal: true
describe 'GH-1319', site: true, stdio: true do
before do
File.write('content/stuff.html', 'abc ')
File.write('Rules', <<~EOS)
compile '/**/*' do
filter :relativize_paths, type: :html
write ext: 'html'
end
EOS
end
before do
Nanoc::CLI.run(%w[compile])
end
example do
expect(File.read('output/stuff.html')).to eq('abc ')
end
end
nanoc-4.11.0/nanoc/spec/nanoc/regressions/gh_1323_spec.rb000066400000000000000000000010321340050175000227600ustar00rootroot00000000000000# frozen_string_literal: true
describe 'GH-1323', site: true, stdio: true do
before do
File.write('content/stuff.html', 'stuff')
File.write('lib/stuff.rb', <<~EOS)
Nanoc::Filter.define(:filter_gh1323) do |content, params = {}|
nil
end
EOS
File.write('Rules', <<~EOS)
compile '/**/*' do
filter :filter_gh1323
end
EOS
end
example do
expect { Nanoc::CLI.run(%w[compile]) }
.to raise_error { |e| e.unwrap.is_a?(Nanoc::Int::Errors::FilterReturnedNil) }
end
end
nanoc-4.11.0/nanoc/spec/nanoc/regressions/gh_1328_spec.rb000066400000000000000000000023001340050175000227640ustar00rootroot00000000000000# frozen_string_literal: true
describe 'GH-1328', site: true, stdio: true do
before do
FileUtils.mkdir_p('content')
File.write('content/foo.md', <<~EOS)
hi
bork bork
EOS
File.write('Rules', <<~EOS)
compile '/*' do
write ext: 'html'
write ext: 'htm'
write ext: 'xhtml'
end
EOS
end
before do
Nanoc::CLI.run([])
end
it 'fails check for foo.html' do
expect { Nanoc::CLI.run(%w[check ilinks]) }
.to raise_error(Nanoc::Int::Errors::GenericTrivial, 'One or more checks failed')
.and output(%r{output/foo\.html:}).to_stdout
end
it 'fails check for foo.xhtml' do
expect { Nanoc::CLI.run(%w[check ilinks]) }
.to raise_error(Nanoc::Int::Errors::GenericTrivial, 'One or more checks failed')
.and output(%r{output/foo\.xhtml:}).to_stdout
end
it 'fails check for foo.htm' do
expect { Nanoc::CLI.run(%w[check ilinks]) }
.to raise_error(Nanoc::Int::Errors::GenericTrivial, 'One or more checks failed')
.and output(%r{output/foo\.htm:}).to_stdout
end
end
nanoc-4.11.0/nanoc/spec/nanoc/regressions/gh_1338_spec.rb000066400000000000000000000007371340050175000230010ustar00rootroot00000000000000# frozen_string_literal: true
describe 'GH-1338', site: true, stdio: true do
before do
File.write('lib/default.rb', <<~EOS)
Nanoc::Filter.define(:gh_1338) do |content, params = {}|
Dir.chdir('..')
content.upcase
end
EOS
File.write('Rules', <<~EOS)
compile '/*' do
filter :gh_1338
write ext: 'html'
end
EOS
File.write('content/foo.txt', 'stuff')
end
example do
Nanoc::CLI.run([])
end
end
nanoc-4.11.0/nanoc/spec/nanoc/regressions/gh_1342_spec.rb000066400000000000000000000006731340050175000227730ustar00rootroot00000000000000# frozen_string_literal: true
describe 'GH-1342', site: true, stdio: true do
before do
File.write('Rules', <<~EOS)
preprocess do
items.create('<%= "hi!" %>', {}, '/hello.html')
end
compile '/*' do
filter :erb
write ext: 'html'
end
postprocess do
@items.each(&:compiled_content)
end
EOS
end
example do
Nanoc::CLI.run([])
Nanoc::CLI.run([])
end
end
nanoc-4.11.0/nanoc/spec/nanoc/regressions/gh_1352_spec.rb000066400000000000000000000004601340050175000227660ustar00rootroot00000000000000# frozen_string_literal: true
describe 'GH-1352', site: true, stdio: true do
before do
File.write('nanoc.yaml', <<~EOS)
environments:
default:
foo: 'bar'
xxx:
EOS
end
example do
expect { Nanoc::CLI.run([]) }.to raise_error(JsonSchema::Error)
end
end
nanoc-4.11.0/nanoc/spec/nanoc/regressions/gh_1358_spec.rb000066400000000000000000000011421340050175000227720ustar00rootroot00000000000000# frozen_string_literal: true
describe 'GH-1358', site: true, stdio: true do
before do
FileUtils.mkdir_p('content')
File.write('content/foo.dat', 'hi')
File.write('content/home.erb', '<%= File.read(@items["/foo.*"].raw_filename) %>')
File.write('Rules', <<~EOS)
ignore '/*.dat'
compile '/*' do
filter :erb
write ext: 'html'
end
EOS
end
example do
Nanoc::CLI.run([])
File.write('content/foo.dat', 'hello')
expect { Nanoc::CLI.run([]) }
.to change { File.read('output/home.html') }
.from('hi')
.to('hello')
end
end
nanoc-4.11.0/nanoc/spec/nanoc/regressions/gh_1372_spec.rb000066400000000000000000000014241340050175000227710ustar00rootroot00000000000000# frozen_string_literal: true
describe 'GH-1372', site: true, stdio: true do
before do
FileUtils.mkdir_p('content')
File.write('content/home.erb', 'hello')
FileUtils.mkdir_p('layouts')
File.write('layouts/default.haml', '#main= yield')
File.write('Rules', <<~EOS)
compile '/*' do
layout '/default.*'
write ext: 'html'
end
layout '/**/*', :haml, remove_whitespace: false
EOS
end
example do
Nanoc::CLI.run(['--verbose'])
File.write('Rules', <<~EOS)
compile '/*' do
layout '/default.*'
write ext: 'html'
end
layout '/**/*', :haml, remove_whitespace: true
EOS
expect { Nanoc::CLI.run(['--verbose']) }
.to output(%r{update.*output/home\.html$}).to_stdout
end
end
nanoc-4.11.0/nanoc/spec/nanoc/regressions/gh_1374_spec.rb000066400000000000000000000006421340050175000227740ustar00rootroot00000000000000# frozen_string_literal: true
describe 'GH-1374', site: true, stdio: true do
before do
FileUtils.mkdir_p('content')
File.write('content/test.md', 'hello')
File.write('Rules', <<~EOS)
compile '/*' do
write nil
end
passthrough '/*'
EOS
end
example do
expect { Nanoc::CLI.run([]) }
.not_to change { File.file?('output/test.md') }
.from(false)
end
end
nanoc-4.11.0/nanoc/spec/nanoc/regressions/gh_1378_spec.rb000066400000000000000000000011401340050175000227720ustar00rootroot00000000000000# frozen_string_literal: true
describe 'GH-1378', site: true, stdio: true do
before do
FileUtils.mkdir_p('content')
File.write('outside.scss', 'p { color: red; }')
File.write('content/style.scss', '@import "../outside.scss";')
File.write('Rules', <<~EOS)
compile '/*' do
filter :sass, syntax: :scss
write ext: 'css'
end
EOS
end
example do
expect { Nanoc::CLI.run([]) }
.to change { File.file?('output/style.css') }
.from(false)
.to(true)
expect(File.read('output/style.css')).to match(/p\s*{\s*color:\s*red;\s*}/)
end
end
nanoc-4.11.0/nanoc/spec/nanoc/regressions/gh_761_spec.rb000066400000000000000000000010641340050175000227120ustar00rootroot00000000000000# frozen_string_literal: true
describe 'GH-761', site: true do
before do
File.write('content/donkey.md', 'Compiled content donkey!')
File.write('layouts/foo.erb', '[<%= @item.compiled_content %>]')
File.write('Rules', <]')
File.open('nanoc.yaml', 'w') do |io|
io << 'string_pattern_type: legacy' << "\n"
io << 'data_sources:' << "\n"
io << ' -' << "\n"
io << ' type: filesystem' << "\n"
io << ' identifier_type: legacy' << "\n"
end
File.write('Rules', <!')
File.write('content/items-view.md', 'Frozen? <%= @items.frozen? %>!')
File.write('Rules', <')
File.write('Rules', < - <%= Time.now.to_f %>",
)
File.write('Rules', <')
File.write('Rules', <')
Nanoc::CLI.run(%w[compile])
expect(File.read('output/hello.html')).to include('donkeys?')
end
end
nanoc-4.11.0/nanoc/spec/nanoc/regressions/gh_913_spec.rb000066400000000000000000000007301340050175000227100ustar00rootroot00000000000000# frozen_string_literal: true
describe 'GH-913', site: true, stdio: true do
before do
File.write('content/hello.html', 'hi!')
File.write('Rules', <')
File.write('layouts/default.xsl', <<~EOS)
EOS
File.write('layouts/snippet.xsl', <<~EOS)
Original Title
Test Body
EOS
File.write('Rules', <<~EOS)
compile '/index.xml' do
layout '/default.xsl'
write '/index.xhtml'
end
layout '/**/*.xsl', :xsl
EOS
end
before do
Nanoc::CLI.run(%w[compile])
end
example do
File.write('layouts/snippet.xsl', <<~EOS)
Changed Title
Test Body
EOS
expect { Nanoc::CLI.run(%w[compile]) }
.to change { File.read('output/index.xhtml') }
.from(/Original Title/)
.to(/<title>Changed Title/)
end
end
��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������nanoc-4.11.0/nanoc/spec/nanoc/regressions/gh_928_spec.rb��������������������������������������������0000664�0000000�0000000�00000000265�13400501750�0022721�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������# frozen_string_literal: true
describe 'GH-928', site: true, stdio: true do
example do
expect { Nanoc::CLI.run(%w[check --list]) }.to output(%r{^ css$}).to_stdout
end
end
�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������nanoc-4.11.0/nanoc/spec/nanoc/regressions/gh_937_spec.rb��������������������������������������������0000664�0000000�0000000�00000001377�13400501750�0022726�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������# frozen_string_literal: true
describe 'GH-937', site: true, stdio: true do
before do
File.write('content/style.sass', ".test\n color: red")
File.write(
'nanoc.yaml',
"sass_style: compact\nenvironments:\n staging:\n sass_style: expanded",
)
File.write('Rules', <<~EOS)
compile '/*.sass' do
filter :sass, style: @config[:sass_style].to_sym
write item.identifier.without_ext + '.css'
end
EOS
end
it 'does not use cache when switching environments' do
Nanoc::CLI.run(%w[compile])
expect(File.read('output/style.css')).to eq(".test { color: red; }\n")
Nanoc::CLI.run(%w[compile --env=staging])
expect(File.read('output/style.css')).to eq(".test {\n color: red;\n}\n")
end
end
�����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������nanoc-4.11.0/nanoc/spec/nanoc/regressions/gh_942_spec.rb��������������������������������������������0000664�0000000�0000000�00000001024�13400501750�0022707�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������# frozen_string_literal: true
describe 'GH-942', site: true, stdio: true do
before do
File.write('content/foo.md', 'Foo!')
File.write('Rules', <<EOS)
compile '/foo.*' do
write '/parent/foo'
end
EOS
File.open('nanoc.yaml', 'w') do |io|
io << 'prune:' << "\n"
io << ' auto_prune: true' << "\n"
end
end
example do
File.write('output/parent', 'Hahaaa! I am a file and not a directory!')
Nanoc::CLI.run(%w[compile])
expect(File.read('output/parent/foo')).to eq('Foo!')
end
end
������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������nanoc-4.11.0/nanoc/spec/nanoc/regressions/gh_947_spec.rb��������������������������������������������0000664�0000000�0000000�00000001052�13400501750�0022715�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������# frozen_string_literal: true
describe 'GH-947', site: true, stdio: true do
before do
File.write('content/foo.md', 'Foo!')
File.write('Rules', <<EOS)
compile '/foo.*' do
write '/foo'
end
EOS
File.open('nanoc.yaml', 'w') do |io|
io << 'prune:' << "\n"
io << ' auto_prune: true' << "\n"
end
end
example do
File.write('output/foo', 'I am an older foo!')
expect { Nanoc::CLI.run(%w[compile]) }.to output(%r{\s+update.* output/foo$}).to_stdout
expect(File.read('output/foo')).to eq('Foo!')
end
end
��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������nanoc-4.11.0/nanoc/spec/nanoc/regressions/gh_948_spec.rb��������������������������������������������0000664�0000000�0000000�00000000602�13400501750�0022716�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������# frozen_string_literal: true
describe 'GH-948', site: true, stdio: true do
before do
File.write('content/foo.md', 'Foo!')
File.open('nanoc.yaml', 'w') do |io|
io << 'prune:' << "\n"
io << ' auto_prune: true' << "\n"
end
FileUtils.rm_rf('output')
end
it 'does not crash when output dir is not present' do
Nanoc::CLI.run(%w[compile])
end
end
������������������������������������������������������������������������������������������������������������������������������nanoc-4.11.0/nanoc/spec/nanoc/regressions/gh_951_spec.rb��������������������������������������������0000664�0000000�0000000�00000000640�13400501750�0022712�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������# frozen_string_literal: true
describe 'GH-951', site: true, stdio: true do
before do
File.write('content/foo.md', 'Foo!')
File.open('nanoc.yaml', 'w') do |io|
io << 'string_pattern_type: legacy' << "\n"
end
File.write('Rules', <<EOS)
passthrough '/foo.md'
EOS
end
it 'copies foo.md' do
Nanoc::CLI.run(%w[compile])
expect(File.file?('output/foo.md')).to eq(true)
end
end
������������������������������������������������������������������������������������������������nanoc-4.11.0/nanoc/spec/nanoc/regressions/gh_954_spec.rb��������������������������������������������0000664�0000000�0000000�00000001775�13400501750�0022727�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������# frozen_string_literal: true
describe 'GH-954', site: true, stdio: true do
before do
File.write('content/foo.md', 'foo <a href="/">root</a>')
File.write('content/bar.md', 'bar <a href="/">root</a>')
File.write('content/bar-copy.md', '<%= @items["/bar.*"].compiled_content(snapshot: :last) %>')
File.write('Rules', <<~EOS)
compile '/foo.*' do
filter :relativize_paths, type: :html unless rep.path.nil?
write item.identifier.without_ext + '.html'
end
compile '/bar.*' do
filter :relativize_paths, type: :html unless rep.path.nil?
end
compile '/bar-copy.*' do
filter :erb
write item.identifier.without_ext + '.html'
end
EOS
end
it 'properly filters foo.md' do
Nanoc::CLI.run(%w[compile])
# Path is relativized
expect(File.read('output/foo.html')).to eq('foo <a href="./">root</a>')
# Path is not relativized
expect(File.read('output/bar-copy.html')).to eq('bar <a href="/">root</a>')
end
end
���nanoc-4.11.0/nanoc/spec/nanoc/regressions/gh_970a_spec.rb�������������������������������������������0000664�0000000�0000000�00000000650�13400501750�0023055�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������# frozen_string_literal: true
describe 'GH-970 (show-rules)', site: true, stdio: true do
before do
File.write('content/foo.md', 'foo')
File.write('Rules', <<~EOS)
compile '/foo.*' do
write '/donkey.html'
end
EOS
end
it 'shows reps' do
expect { Nanoc::CLI.run(%w[show-rules --no-color]) }.to(
output(/^Item \/foo\.md:\n Rep default: \/foo\.\*$/).to_stdout,
)
end
end
����������������������������������������������������������������������������������������nanoc-4.11.0/nanoc/spec/nanoc/regressions/gh_970b_spec.rb�������������������������������������������0000664�0000000�0000000�00000003043�13400501750�0023055�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������# frozen_string_literal: true
describe 'GH-970 (show-data)', site: true, stdio: true do
before do
File.write('content/foo.md', 'foo')
File.write('content/bar.md', '<%= @items["/foo.*"].compiled_content %>')
File.write('Rules', <<~EOS)
compile '/foo.*' do
write '/foo.html'
end
compile '/bar.*' do
filter :erb
write '/bar.html'
end
EOS
end
before { Nanoc::CLI.run(%w[compile]) }
it 'shows default rep outdatedness' do
expect { Nanoc::CLI.run(%w[show-data --no-color]) }.to(
output(/^item \/foo\.md, rep default:\n is not outdated/).to_stdout,
)
expect { Nanoc::CLI.run(%w[show-data --no-color]) }.to(
output(/^item \/bar\.md, rep default:\n is not outdated/).to_stdout,
)
end
it 'shows file as outdated after modification' do
File.write('content/bar.md', 'JUST BAR!')
expect { Nanoc::CLI.run(%w[show-data --no-color]) }.to(
output(/^item \/foo\.md, rep default:\n is not outdated/).to_stdout,
)
expect { Nanoc::CLI.run(%w[show-data --no-color]) }.to(
output(/^item \/bar\.md, rep default:\n is outdated:/).to_stdout,
)
end
it 'shows file and dependencies as outdated after modification' do
File.write('content/foo.md', 'FOO!')
expect { Nanoc::CLI.run(%w[show-data --no-color]) }.to(
output(/^item \/foo\.md, rep default:\n is outdated:/).to_stdout,
)
expect { Nanoc::CLI.run(%w[show-data --no-color]) }.to(
output(/^item \/bar\.md, rep default:\n is outdated:/).to_stdout,
)
end
end
���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������nanoc-4.11.0/nanoc/spec/nanoc/regressions/gh_974_spec.rb��������������������������������������������0000664�0000000�0000000�00000000607�13400501750�0022722�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������# frozen_string_literal: true
describe 'GH-974', site: true, stdio: true do
before do
File.write('content/foo.md', 'foo')
File.write('Rules', <<~EOS)
compile '/foo.*' do
write item.identifier
end
EOS
end
it 'writes to path corresponding to identifier' do
Nanoc::CLI.run(%w[compile])
expect(File.file?('output/foo.md')).to eq(true)
end
end
�������������������������������������������������������������������������������������������������������������������������nanoc-4.11.0/nanoc/spec/nanoc/regressions/gh_981_spec.rb��������������������������������������������0000664�0000000�0000000�00000001102�13400501750�0022707�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������# frozen_string_literal: true
describe 'GH-981', site: true, stdio: true do
before do
File.write('content/foo.md', 'I am foo!')
File.write('Rules', <<EOS)
compile '/foo.*' do
filter :erb, stuff: self
write '/foo.html'
end
EOS
end
it 'creates at first' do
expect { Nanoc::CLI.run(%w[compile --verbose]) }.to output(%r{create.*output/foo\.html$}).to_stdout
end
it 'skips the item on second try' do
Nanoc::CLI.run(%w[compile])
expect { Nanoc::CLI.run(%w[compile --verbose]) }.to output(%r{skip.*output/foo\.html$}).to_stdout
end
end
��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������nanoc-4.11.0/nanoc/spec/nanoc/rule_dsl/�������������������������������������������������������������0000775�0000000�0000000�00000000000�13400501750�0017625�5����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������nanoc-4.11.0/nanoc/spec/nanoc/rule_dsl/action_recorder_spec.rb��������������������������������������0000664�0000000�0000000�00000014560�13400501750�0024334�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������# frozen_string_literal: true
describe Nanoc::RuleDSL::ActionRecorder do
let(:recorder) { described_class.new(rep) }
let(:action_sequence) { recorder.action_sequence }
let(:item) { Nanoc::Int::Item.new('stuff', {}, '/foo.md') }
let(:rep) { Nanoc::Int::ItemRep.new(item, :default) }
describe '#filter' do
it 'records filter call without arguments' do
recorder.filter(:erb)
expect(action_sequence.size).to eql(1)
expect(action_sequence[0]).to be_a(Nanoc::Int::ProcessingActions::Filter)
expect(action_sequence[0].filter_name).to eql(:erb)
expect(action_sequence[0].params).to eql({})
end
it 'records filter call with arguments' do
recorder.filter(:erb, x: 123)
expect(action_sequence.size).to eql(1)
expect(action_sequence[0]).to be_a(Nanoc::Int::ProcessingActions::Filter)
expect(action_sequence[0].filter_name).to eql(:erb)
expect(action_sequence[0].params).to eql(x: 123)
end
end
describe '#layout' do
it 'records layout call without arguments' do
recorder.layout('/default.*')
expect(action_sequence.size).to eql(2)
expect(action_sequence[0]).to be_a(Nanoc::Int::ProcessingActions::Snapshot)
expect(action_sequence[0].snapshot_names).to eql([:pre])
expect(action_sequence[0].paths).to be_empty
expect(action_sequence[1]).to be_a(Nanoc::Int::ProcessingActions::Layout)
expect(action_sequence[1].layout_identifier).to eql('/default.*')
expect(action_sequence[1].params).to eql({})
end
it 'records layout call with arguments' do
recorder.layout('/default.*', donkey: 123)
expect(action_sequence.size).to eql(2)
expect(action_sequence[0]).to be_a(Nanoc::Int::ProcessingActions::Snapshot)
expect(action_sequence[0].snapshot_names).to eql([:pre])
expect(action_sequence[0].paths).to be_empty
expect(action_sequence[1]).to be_a(Nanoc::Int::ProcessingActions::Layout)
expect(action_sequence[1].layout_identifier).to eql('/default.*')
expect(action_sequence[1].params).to eql(donkey: 123)
end
it 'fails when passed a symbol' do
expect { recorder.layout(:default, donkey: 123) }.to raise_error(ArgumentError)
end
end
describe '#snapshot' do
context 'snapshot already exists' do
before do
recorder.snapshot(:foo)
end
it 'raises when creating same snapshot' do
expect { recorder.snapshot(:foo) }
.to raise_error(Nanoc::Int::Errors::CannotCreateMultipleSnapshotsWithSameName)
end
end
context 'no arguments' do
subject { recorder.snapshot(:foo) }
it 'records' do
subject
expect(action_sequence.size).to eql(1)
expect(action_sequence[0]).to be_a(Nanoc::Int::ProcessingActions::Snapshot)
expect(action_sequence[0].snapshot_names).to eql([:foo])
expect(action_sequence[0].paths).to be_empty
end
end
context 'final argument' do
subject { recorder.snapshot(:foo, subject_params) }
let(:subject_params) { {} }
context 'routing rule does not exist' do
context 'no explicit path given' do
subject { recorder.snapshot(:foo, subject_params) }
it 'records' do
subject
expect(action_sequence.size).to eql(1)
expect(action_sequence[0]).to be_a(Nanoc::Int::ProcessingActions::Snapshot)
expect(action_sequence[0].snapshot_names).to eql([:foo])
expect(action_sequence[0].paths).to be_empty
end
it 'keeps skip_routing_rule' do
expect { subject }
.not_to change { recorder.snapshots_for_which_to_skip_routing_rule }
.from(Set.new)
end
end
context 'explicit path given as string' do
let(:subject_params) { { path: '/routed-foo.html' } }
it 'records' do
subject
expect(action_sequence.size).to eql(1)
expect(action_sequence[0]).to be_a(Nanoc::Int::ProcessingActions::Snapshot)
expect(action_sequence[0].snapshot_names).to eql([:foo])
expect(action_sequence[0].paths).to eql(['/routed-foo.html'])
end
it 'sets skip_routing_rule' do
expect { subject }
.to change { recorder.snapshots_for_which_to_skip_routing_rule }
.from(Set.new)
.to(Set.new([:foo]))
end
end
context 'explicit path given as identifier' do
let(:subject_params) { { path: Nanoc::Identifier.from('/routed-foo.html') } }
it 'records' do
subject
expect(action_sequence.size).to eql(1)
expect(action_sequence[0]).to be_a(Nanoc::Int::ProcessingActions::Snapshot)
expect(action_sequence[0].snapshot_names).to eql([:foo])
expect(action_sequence[0].paths).to eql(['/routed-foo.html'])
end
it 'sets skip_routing_rule' do
expect { subject }
.to change { recorder.snapshots_for_which_to_skip_routing_rule }
.from(Set.new)
.to(Set.new([:foo]))
end
end
context 'explicit path given as nil' do
let(:subject_params) { { path: nil } }
it 'records' do
subject
expect(action_sequence.size).to eql(1)
expect(action_sequence[0]).to be_a(Nanoc::Int::ProcessingActions::Snapshot)
expect(action_sequence[0].snapshot_names).to eql([:foo])
expect(action_sequence[0].paths).to be_empty
end
it 'sets skip_routing_rule' do
expect { subject }
.to change { recorder.snapshots_for_which_to_skip_routing_rule }
.from(Set.new)
.to(Set.new([:foo]))
end
end
end
end
it 'raises when given unknown arguments' do
expect { recorder.snapshot(:foo, animal: 'giraffe') }
.to raise_error(ArgumentError)
end
it 'can create multiple snapshots with different names' do
recorder.snapshot(:foo)
recorder.snapshot(:bar)
expect(action_sequence.size).to eql(2)
expect(action_sequence[0]).to be_a(Nanoc::Int::ProcessingActions::Snapshot)
expect(action_sequence[0].snapshot_names).to eql([:foo])
expect(action_sequence[1]).to be_a(Nanoc::Int::ProcessingActions::Snapshot)
expect(action_sequence[1].snapshot_names).to eql([:bar])
end
end
end
������������������������������������������������������������������������������������������������������������������������������������������������nanoc-4.11.0/nanoc/spec/nanoc/rule_dsl/action_sequence_calculator_spec.rb���������������������������0000664�0000000�0000000�00000017176�13400501750�0026556�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������# frozen_string_literal: true
describe(Nanoc::RuleDSL::ActionSequenceCalculator) do
subject(:action_sequence_calculator) do
described_class.new(site: site, rules_collection: rules_collection)
end
let(:rules_collection) { Nanoc::RuleDSL::RulesCollection.new }
let(:config) { Nanoc::Int::Configuration.new(dir: Dir.getwd).with_defaults }
let(:items) { Nanoc::Int::ItemCollection.new(config) }
let(:layouts) { Nanoc::Int::LayoutCollection.new(config) }
let(:data_source_class) do
Class.new(Nanoc::DataSource) do
def items
@config.fetch(:items)
end
def layouts
@config.fetch(:layouts)
end
end
end
let(:data_source) do
data_source_config = { items: items, layouts: layouts }
data_source_class.new(config, '/', '/', data_source_config)
end
let(:site) do
Nanoc::Int::Site.new(config: config, code_snippets: [], data_source: data_source)
end
describe '#[]' do
subject { action_sequence_calculator[obj] }
context 'with item rep' do
let(:obj) { Nanoc::Int::ItemRep.new(item, :csv) }
let(:item) { Nanoc::Int::Item.new('content', {}, Nanoc::Identifier.from('/list.md')) }
context 'no rules exist' do
it 'raises error' do
error = Nanoc::RuleDSL::ActionSequenceCalculator::NoActionSequenceForItemRepException
expect { subject }.to raise_error(error)
end
end
context 'rules exist' do
before do
rules_proc = proc do
filter :erb, speed: :over_9000
layout '/default.*'
filter :typohero
end
rule = Nanoc::RuleDSL::CompilationRule.new(Nanoc::Int::Pattern.from('/list.*'), :csv, rules_proc)
rules_collection.add_item_compilation_rule(rule)
end
example do
subject
expect(subject[0]).to be_a(Nanoc::Int::ProcessingActions::Snapshot)
expect(subject[0].snapshot_names).to eql([:raw])
expect(subject[0].paths).to be_empty
expect(subject[1]).to be_a(Nanoc::Int::ProcessingActions::Filter)
expect(subject[1].filter_name).to eql(:erb)
expect(subject[1].params).to eql(speed: :over_9000)
expect(subject[2]).to be_a(Nanoc::Int::ProcessingActions::Snapshot)
expect(subject[2].snapshot_names).to eql([:pre])
expect(subject[2].paths).to be_empty
expect(subject[3]).to be_a(Nanoc::Int::ProcessingActions::Layout)
expect(subject[3].layout_identifier).to eql('/default.*')
expect(subject[3].params).to be_nil
expect(subject[4]).to be_a(Nanoc::Int::ProcessingActions::Filter)
expect(subject[4].filter_name).to eql(:typohero)
expect(subject[4].params).to eql({})
expect(subject[5]).to be_a(Nanoc::Int::ProcessingActions::Snapshot)
expect(subject[5].snapshot_names).to eql(%i[post last])
expect(subject[5].paths).to be_empty
expect(subject.size).to eql(6)
end
end
context 'no routing rule exists' do
before do
# Add compilation rule
compilation_rule = Nanoc::RuleDSL::CompilationRule.new(Nanoc::Int::Pattern.from('/list.*'), :csv, proc {})
rules_collection.add_item_compilation_rule(compilation_rule)
end
example do
subject
expect(subject[0]).to be_a(Nanoc::Int::ProcessingActions::Snapshot)
expect(subject[0].snapshot_names).to eql(%i[raw last pre])
expect(subject[0].paths).to be_empty
expect(subject.size).to eql(1)
end
end
context 'routing rule exists' do
before do
# Add compilation rule
compilation_rule = Nanoc::RuleDSL::CompilationRule.new(Nanoc::Int::Pattern.from('/list.*'), :csv, proc {})
rules_collection.add_item_compilation_rule(compilation_rule)
# Add routing rule
routing_rule = Nanoc::RuleDSL::RoutingRule.new(Nanoc::Int::Pattern.from('/list.*'), :csv, proc { '/foo.md' }, snapshot_name: :last)
rules_collection.add_item_routing_rule(routing_rule)
end
example do
subject
expect(subject[0]).to be_a(Nanoc::Int::ProcessingActions::Snapshot)
expect(subject[0].snapshot_names).to eql(%i[raw last pre])
expect(subject[0].paths).to eq(['/foo.md'])
expect(subject.size).to eql(1)
end
end
context 'routing rule for other rep exists' do
before do
# Add compilation rule
compilation_rule = Nanoc::RuleDSL::CompilationRule.new(Nanoc::Int::Pattern.from('/list.*'), :csv, proc {})
rules_collection.add_item_compilation_rule(compilation_rule)
# Add routing rule
routing_rule = Nanoc::RuleDSL::RoutingRule.new(Nanoc::Int::Pattern.from('/list.*'), :abc, proc { '/foo.md' }, snapshot_name: :last)
rules_collection.add_item_routing_rule(routing_rule)
end
example do
subject
expect(subject[0]).to be_a(Nanoc::Int::ProcessingActions::Snapshot)
expect(subject[0].snapshot_names).to eql(%i[raw last pre])
expect(subject[0].paths).to be_empty
expect(subject.size).to eql(1)
end
end
end
context 'with layout' do
let(:obj) { Nanoc::Int::Layout.new('content', {}, '/default.erb') }
context 'no rules exist' do
it 'raises error' do
error = Nanoc::RuleDSL::ActionSequenceCalculator::NoActionSequenceForLayoutException
expect { subject }.to raise_error(error)
end
end
context 'rule exists' do
before do
pat = Nanoc::Int::Pattern.from('/*.erb')
rules_collection.layout_filter_mapping[pat] = [:erb, { x: 123 }]
end
it 'contains memory for the rule' do
expect(subject.size).to eql(1)
expect(subject[0]).to be_a(Nanoc::Int::ProcessingActions::Filter)
expect(subject[0].filter_name).to eql(:erb)
expect(subject[0].params).to eql(x: 123)
end
end
end
context 'with something else' do
let(:obj) { :donkey }
it 'errors' do
error = Nanoc::RuleDSL::ActionSequenceCalculator::UnsupportedObjectTypeException
expect { subject }.to raise_error(error)
end
end
end
describe '#compact_snapshots' do
subject { action_sequence_calculator.compact_snapshots(action_sequence) }
let(:action_sequence) do
Nanoc::Int::ActionSequence.build(rep) do |b|
b.add_snapshot(:a1, nil)
b.add_snapshot(:a2, '/a2.md')
b.add_snapshot(:a3, nil)
b.add_filter(:erb, awesomeness: 'high')
b.add_snapshot(:b1, '/b1.md')
b.add_snapshot(:b2, nil)
b.add_snapshot(:b3, '/b3.md')
b.add_filter(:erb, awesomeness: 'high')
b.add_snapshot(:c, nil)
end
end
let(:item) { Nanoc::Int::Item.new('asdf', {}, '/foo.md') }
let(:rep) { Nanoc::Int::ItemRep.new(item, :default) }
example do
expect(subject[0]).to be_a(Nanoc::Int::ProcessingActions::Snapshot)
expect(subject[0].snapshot_names).to eql(%i[a1 a2 a3])
expect(subject[0].paths).to eql(['/a2.md'])
expect(subject[1]).to be_a(Nanoc::Int::ProcessingActions::Filter)
expect(subject[2]).to be_a(Nanoc::Int::ProcessingActions::Snapshot)
expect(subject[2].snapshot_names).to eql(%i[b1 b2 b3])
expect(subject[2].paths).to eql(['/b1.md', '/b3.md'])
expect(subject[3]).to be_a(Nanoc::Int::ProcessingActions::Filter)
expect(subject[4]).to be_a(Nanoc::Int::ProcessingActions::Snapshot)
expect(subject[4].snapshot_names).to eql([:c])
expect(subject[4].paths).to be_empty
expect(subject.size).to eql(5)
end
end
end
��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������nanoc-4.11.0/nanoc/spec/nanoc/rule_dsl/rule_context_spec.rb�����������������������������������������0000664�0000000�0000000�00000025206�13400501750�0023704�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������# frozen_string_literal: true
shared_examples 'a rule context' do
let(:item_identifier) { Nanoc::Identifier.new('/foo.md') }
let(:item) { Nanoc::Int::Item.new('content', {}, item_identifier) }
let(:config) { Nanoc::Int::Configuration.new(dir: Dir.getwd) }
let(:items) { Nanoc::Int::ItemCollection.new(config) }
let(:layouts) { Nanoc::Int::LayoutCollection.new(config) }
let(:site) do
Nanoc::Int::Site.new(
config: config,
code_snippets: [],
data_source: data_source,
)
end
let(:data_source) do
Nanoc::Int::InMemDataSource.new(items, layouts)
end
let(:rep) { Nanoc::Int::ItemRep.new(item, :default) }
let(:reps) { double(:reps) }
let(:compilation_context) { double(:compilation_context) }
let(:view_context) do
Nanoc::ViewContextForPreCompilation.new(items: items)
end
let(:dependency_tracker) { double(:dependency_tracker) }
describe '#initialize' do
it 'wraps objects in view classes' do
expect(subject.rep.class).to eql(Nanoc::BasicItemRepView)
expect(subject.item.class).to eql(Nanoc::BasicItemView)
expect(subject.config.class).to eql(Nanoc::ConfigView)
expect(subject.layouts.class).to eql(Nanoc::LayoutCollectionView)
expect(subject.items.class).to eql(Nanoc::ItemCollectionWithoutRepsView)
end
it 'contains the right objects' do
expect(rule_context.rep._unwrap).to eql(rep)
expect(rule_context.item._unwrap).to eql(item)
expect(rule_context.config._unwrap).to eql(config)
expect(rule_context.layouts._unwrap).to eql(layouts)
expect(rule_context.items._unwrap).to eql(items)
end
end
describe '#item' do
subject { rule_context.item }
it 'is a view without reps access' do
expect(subject.class).to eql(Nanoc::BasicItemView)
end
it 'contains the right item' do
expect(subject._unwrap).to eql(item)
end
context 'with legacy identifier and children/parent' do
let(:item_identifier) { Nanoc::Identifier.new('/foo/', type: :legacy) }
let(:parent_identifier) { Nanoc::Identifier.new('/', type: :legacy) }
let(:parent) { Nanoc::Int::Item.new('parent', {}, parent_identifier) }
let(:child_identifier) { Nanoc::Identifier.new('/foo/bar/', type: :legacy) }
let(:child) { Nanoc::Int::Item.new('child', {}, child_identifier) }
let(:items) do
Nanoc::Int::ItemCollection.new(config, [item, parent, child])
end
it 'has a parent' do
expect(subject.parent._unwrap).to eql(parent)
end
it 'wraps the parent in a view without reps access' do
expect(subject.parent.class).to eql(Nanoc::BasicItemView)
expect(subject.parent).not_to respond_to(:compiled_content)
expect(subject.parent).not_to respond_to(:path)
expect(subject.parent).not_to respond_to(:reps)
end
it 'has children' do
expect(subject.children.map(&:_unwrap)).to eql([child])
end
it 'wraps the children in a view without reps access' do
expect(subject.children.map(&:class)).to eql([Nanoc::BasicItemView])
expect(subject.children[0]).not_to respond_to(:compiled_content)
expect(subject.children[0]).not_to respond_to(:path)
expect(subject.children[0]).not_to respond_to(:reps)
end
end
end
describe '#items' do
subject { rule_context.items }
let(:item_identifier) { Nanoc::Identifier.new('/foo/', type: :legacy) }
let(:parent_identifier) { Nanoc::Identifier.new('/', type: :legacy) }
let(:parent) { Nanoc::Int::Item.new('parent', {}, parent_identifier) }
let(:child_identifier) { Nanoc::Identifier.new('/foo/bar/', type: :legacy) }
let(:child) { Nanoc::Int::Item.new('child', {}, child_identifier) }
let(:items) do
Nanoc::Int::ItemCollection.new(config, [item, parent, child])
end
it 'is a view without reps access' do
expect(subject.class).to eql(Nanoc::ItemCollectionWithoutRepsView)
end
it 'contains all items' do
expect(subject._unwrap).to match_array([item, parent, child])
end
it 'provides no rep access' do
allow(dependency_tracker).to receive(:bounce).and_return(nil)
expect(subject['/']).not_to be_nil
expect(subject['/']).not_to respond_to(:compiled_content)
expect(subject['/']).not_to respond_to(:path)
expect(subject['/']).not_to respond_to(:reps)
expect(subject['/foo/']).not_to be_nil
expect(subject['/foo/']).not_to respond_to(:compiled_content)
expect(subject['/foo/']).not_to respond_to(:path)
expect(subject['/foo/']).not_to respond_to(:reps)
expect(subject['/foo/bar/']).not_to be_nil
expect(subject['/foo/bar/']).not_to respond_to(:compiled_content)
expect(subject['/foo/bar/']).not_to respond_to(:path)
expect(subject['/foo/bar/']).not_to respond_to(:reps)
end
end
end
describe(Nanoc::RuleDSL::RoutingRuleContext) do
subject(:rule_context) do
described_class.new(rep: rep, site: site, view_context: view_context)
end
let(:item_identifier) { Nanoc::Identifier.new('/foo.md') }
let(:item) { Nanoc::Int::Item.new('content', {}, item_identifier) }
let(:rep) { Nanoc::Int::ItemRep.new(item, :default) }
let(:config) { Nanoc::Int::Configuration.new(dir: Dir.getwd) }
let(:items) { Nanoc::Int::ItemCollection.new(config) }
let(:site) do
Nanoc::Int::Site.new(
config: config,
code_snippets: [],
data_source: data_source,
)
end
let(:view_context) do
Nanoc::ViewContextForPreCompilation.new(items: items)
end
it_behaves_like 'a rule context'
end
describe(Nanoc::RuleDSL::CompilationRuleContext) do
subject(:rule_context) do
described_class.new(rep: rep, site: site, recorder: recorder, view_context: view_context)
end
let(:item_identifier) { Nanoc::Identifier.new('/foo.md') }
let(:item) { Nanoc::Int::Item.new('content', {}, item_identifier) }
let(:rep) { Nanoc::Int::ItemRep.new(item, :default) }
let(:config) { Nanoc::Int::Configuration.new(dir: Dir.getwd) }
let(:items) { Nanoc::Int::ItemCollection.new(config) }
let(:layouts) { Nanoc::Int::LayoutCollection.new(config) }
let(:site) do
Nanoc::Int::Site.new(
config: config,
code_snippets: [],
data_source: data_source,
)
end
let(:data_source) do
Nanoc::Int::InMemDataSource.new(items, layouts)
end
let(:rep) { Nanoc::Int::ItemRep.new(item, :default) }
let(:view_context) do
Nanoc::ViewContextForPreCompilation.new(items: items)
end
let(:recorder) { Nanoc::RuleDSL::ActionRecorder.new(rep) }
it_behaves_like 'a rule context'
describe '#filter' do
subject { rule_context.filter(filter_name, filter_args) }
let(:filter_name) { :donkey }
let(:filter_args) { { color: 'grey' } }
it 'makes a request to the recorder' do
expect(recorder).to receive(:filter).with(filter_name, filter_args)
subject
end
end
describe '#layout' do
subject { rule_context.layout(layout_identifier, extra_filter_args) }
let(:layout_identifier) { '/default.*' }
let(:extra_filter_args) { { color: 'grey' } }
it 'makes a request to the recorder' do
expect(recorder).to receive(:layout).with(layout_identifier, extra_filter_args)
subject
end
end
describe '#snapshot' do
subject { rule_context.snapshot(snapshot_name, path: path) }
let(:snapshot_name) { :for_snippet }
let(:path) { '/foo.html' }
it 'makes a request to the recorder' do
expect(recorder).to receive(:snapshot).with(:for_snippet, path: '/foo.html')
subject
end
end
describe '#write' do
context 'with string' do
context 'calling once' do
subject { rule_context.write('/foo.html') }
it 'makes a request to the recorder' do
expect(recorder).to receive(:snapshot).with(:_0, path: '/foo.html')
subject
end
end
context 'calling twice' do
subject do
rule_context.write('/foo.html')
rule_context.write('/bar.html')
end
it 'makes two requests to the recorder with unique snapshot names' do
expect(recorder).to receive(:snapshot).with(:_0, path: '/foo.html')
expect(recorder).to receive(:snapshot).with(:_1, path: '/bar.html')
subject
end
end
end
context 'with identifier' do
context 'calling once' do
subject { rule_context.write(identifier) }
let(:identifier) { Nanoc::Identifier.new('/foo.html') }
it 'makes a request to the recorder' do
expect(recorder).to receive(:snapshot).with(:_0, path: '/foo.html')
subject
end
end
context 'calling twice' do
subject do
rule_context.write(identifier_a)
rule_context.write(identifier_b)
end
let(:identifier_a) { Nanoc::Identifier.new('/foo.html') }
let(:identifier_b) { Nanoc::Identifier.new('/bar.html') }
it 'makes two requests to the recorder with unique snapshot names' do
expect(recorder).to receive(:snapshot).with(:_0, path: '/foo.html')
expect(recorder).to receive(:snapshot).with(:_1, path: '/bar.html')
subject
end
end
end
context 'with :ext, without period' do
context 'calling once' do
subject { rule_context.write(ext: 'html') }
it 'makes a request to the recorder' do
expect(recorder).to receive(:snapshot).with(:_0, path: '/foo.html')
subject
end
end
context 'calling twice' do
subject do
rule_context.write(ext: 'html')
rule_context.write(ext: 'htm')
end
it 'makes a request to the recorder' do
expect(recorder).to receive(:snapshot).with(:_0, path: '/foo.html')
expect(recorder).to receive(:snapshot).with(:_1, path: '/foo.htm')
subject
end
end
end
context 'with :ext, with period' do
context 'calling once' do
subject { rule_context.write(ext: '.html') }
it 'makes a request to the recorder' do
expect(recorder).to receive(:snapshot).with(:_0, path: '/foo.html')
subject
end
end
context 'calling twice' do
subject do
rule_context.write(ext: '.html')
rule_context.write(ext: '.htm')
end
it 'makes a request to the recorder' do
expect(recorder).to receive(:snapshot).with(:_0, path: '/foo.html')
expect(recorder).to receive(:snapshot).with(:_1, path: '/foo.htm')
subject
end
end
end
context 'with nil' do
subject { rule_context.write(nil) }
it 'makes a request to the recorder' do
expect(recorder).to receive(:snapshot).with(:_0, path: nil)
subject
end
end
end
end
������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������nanoc-4.11.0/nanoc/spec/nanoc/rule_dsl/rule_spec.rb�������������������������������������������������0000664�0000000�0000000�00000010366�13400501750�0022141�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������# frozen_string_literal: true
shared_examples 'a generic rule' do
subject(:rule) do
described_class.new(pattern, :xml, block)
end
let(:pattern) { Nanoc::Int::Pattern.from(%r{/(.*)/(.*)/}) }
let(:block) { proc {} }
describe '#matches' do
subject { rule.matches(identifier) }
context 'does not match' do
let(:identifier) { Nanoc::Identifier.new('/moo/', type: :legacy) }
it { is_expected.to be_nil }
end
context 'matches' do
let(:identifier) { Nanoc::Identifier.new('/foo/bar/', type: :legacy) }
it { is_expected.to eql(%w[foo bar]) }
end
end
describe '#initialize' do
subject { rule }
its(:rep_name) { is_expected.to eql(:xml) }
its(:pattern) { is_expected.to eql(pattern) }
end
describe '#applicable_to?' do
subject { rule.applicable_to?(item) }
let(:item) { Nanoc::Int::Item.new('', {}, '/foo.md') }
context 'pattern matches' do
let(:pattern) { Nanoc::Int::Pattern.from(%r{^/foo.*}) }
it { is_expected.to be }
end
context 'pattern does not match' do
let(:pattern) { Nanoc::Int::Pattern.from(%r{^/bar.*}) }
it { is_expected.not_to be }
end
end
end
shared_examples 'Rule#apply_to' do
let(:block) do
proc { self }
end
let(:item) { Nanoc::Int::Item.new('', {}, '/foo.md') }
let(:rep) { Nanoc::Int::ItemRep.new(item, :amazings) }
let(:site) { Nanoc::Int::Site.new(config: config, data_source: data_source, code_snippets: []) }
let(:data_source) { Nanoc::Int::InMemDataSource.new(items, layouts) }
let(:config) { Nanoc::Int::Configuration.new(dir: Dir.getwd) }
let(:view_context) { Nanoc::ViewContextForPreCompilation.new(items: items) }
let(:items) { Nanoc::Int::ItemCollection.new(config, []) }
let(:layouts) { Nanoc::Int::LayoutCollection.new(config, []) }
it 'makes rep accessible' do
expect(subject.instance_eval { rep }._unwrap).to eql(rep)
expect(subject.instance_eval { @rep }._unwrap).to eql(rep)
end
it 'makes item_rep accessible' do
expect(subject.instance_eval { item_rep }._unwrap).to eql(rep)
expect(subject.instance_eval { @item_rep }._unwrap).to eql(rep)
end
it 'makes item accessible' do
expect(subject.instance_eval { item }._unwrap).to eql(item)
expect(subject.instance_eval { @item }._unwrap).to eql(item)
end
it 'makes items accessible' do
expect(subject.instance_eval { items }._unwrap).to eql(items)
expect(subject.instance_eval { @items }._unwrap).to eql(items)
end
it 'makes layouts accessible' do
expect(subject.instance_eval { layouts }._unwrap).to eql(layouts)
expect(subject.instance_eval { @layouts }._unwrap).to eql(layouts)
end
it 'makes config accessible' do
expect(subject.instance_eval { config }._unwrap).to eql(config)
expect(subject.instance_eval { @config }._unwrap).to eql(config)
end
end
describe Nanoc::RuleDSL::RoutingRule do
subject(:rule) do
described_class.new(pattern, :xml, block)
end
let(:pattern) { Nanoc::Int::Pattern.from(%r{/(.*)/(.*)/}) }
let(:block) { proc {} }
it_behaves_like 'a generic rule'
describe '#initialize' do
context 'without snapshot_name' do
subject { described_class.new(pattern, :xml, proc {}) }
its(:rep_name) { is_expected.to eql(:xml) }
its(:pattern) { is_expected.to eql(pattern) }
its(:snapshot_name) { is_expected.to be_nil }
end
context 'with snapshot_name' do
subject { described_class.new(pattern, :xml, proc {}, snapshot_name: :donkey) }
its(:rep_name) { is_expected.to eql(:xml) }
its(:pattern) { is_expected.to eql(pattern) }
its(:snapshot_name) { is_expected.to eql(:donkey) }
end
end
describe '#apply_to' do
subject { rule.apply_to(rep, site: site, view_context: view_context) }
it_behaves_like 'Rule#apply_to'
end
end
describe Nanoc::RuleDSL::CompilationRule do
subject(:rule) do
described_class.new(pattern, :xml, block)
end
let(:pattern) { Nanoc::Int::Pattern.from(%r{/(.*)/(.*)/}) }
let(:block) { proc {} }
it_behaves_like 'a generic rule'
describe '#apply_to' do
subject { rule.apply_to(rep, site: site, recorder: recorder, view_context: view_context) }
let(:recorder) { Nanoc::RuleDSL::ActionRecorder.new(rep) }
let(:rep) { nil }
it_behaves_like 'Rule#apply_to'
end
end
��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������nanoc-4.11.0/nanoc/spec/nanoc/rule_dsl/rules_collection_spec.rb�������������������������������������0000664�0000000�0000000�00000017316�13400501750�0024541�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������# frozen_string_literal: true
describe Nanoc::RuleDSL::RulesCollection do
let(:rules_collection) { described_class.new }
describe '#data' do
subject { rules_collection.data }
it 'is nil by default' do
expect(subject).to be_nil
end
it 'can be set' do
rules_collection.data = 'asdf'
expect(subject).to eq('asdf')
end
end
describe '#compilation_rule_for' do
let(:item) { Nanoc::Int::Item.new('content', {}, '/foo.md') }
let(:rep) { Nanoc::Int::ItemRep.new(item, rep_name) }
let(:rep_name) { :default }
subject { rules_collection.compilation_rule_for(rep) }
context 'no rules' do
it 'is nil' do
expect(subject).to be_nil
end
end
context 'some rules, none matching' do
before do
rules_collection.add_item_compilation_rule(rule)
end
let(:rule) do
Nanoc::RuleDSL::CompilationRule.new(Nanoc::Int::Pattern.from('/bar.*'), :default, proc {})
end
it 'is nil' do
expect(subject).to be_nil
end
end
context 'some rules, one matching' do
before do
rules_collection.add_item_compilation_rule(rule_a)
rules_collection.add_item_compilation_rule(rule_b)
end
let(:rule_a) do
Nanoc::RuleDSL::CompilationRule.new(Nanoc::Int::Pattern.from('/foo.*'), :default, proc {})
end
let(:rule_b) do
Nanoc::RuleDSL::CompilationRule.new(Nanoc::Int::Pattern.from('/bar.*'), :default, proc {})
end
context 'rep name does not match' do
let(:rep_name) { :platypus }
it 'is nil' do
expect(subject).to be_nil
end
end
context 'rep name matches' do
it 'is the rule' do
expect(subject).to equal(rule_a)
end
end
end
context 'some rules, multiple matching' do
before do
rules_collection.add_item_compilation_rule(rule_a)
rules_collection.add_item_compilation_rule(rule_b)
rules_collection.add_item_compilation_rule(rule_c)
end
let(:rule_a) do
Nanoc::RuleDSL::CompilationRule.new(Nanoc::Int::Pattern.from('/foo.*'), :default, proc {})
end
let(:rule_b) do
Nanoc::RuleDSL::CompilationRule.new(Nanoc::Int::Pattern.from('/*.*'), :default, proc {})
end
let(:rule_c) do
Nanoc::RuleDSL::CompilationRule.new(Nanoc::Int::Pattern.from('/*.*'), :foo, proc {})
end
context 'no rep name matches' do
let(:rep_name) { :platypus }
it 'is the first matching rule' do
expect(subject).to be_nil
end
end
context 'one rep name matches' do
let(:rep_name) { :foo }
it 'is the first matching rule' do
expect(subject).to equal(rule_c)
end
end
context 'multiple rep names match' do
it 'is the first matching rule' do
expect(subject).to equal(rule_a)
end
end
end
end
describe '#item_compilation_rules_for' do
let(:item) { Nanoc::Int::Item.new('content', {}, '/foo.md') }
subject { rules_collection.item_compilation_rules_for(item) }
context 'no rules' do
it 'is none' do
expect(subject).to be_empty
end
end
context 'some rules, none matching' do
before do
rules_collection.add_item_compilation_rule(rule)
end
let(:rule) do
Nanoc::RuleDSL::CompilationRule.new(Nanoc::Int::Pattern.from('/bar.*'), :default, proc {})
end
it 'is none' do
expect(subject).to be_empty
end
end
context 'some rules, one matching' do
before do
rules_collection.add_item_compilation_rule(rule_a)
rules_collection.add_item_compilation_rule(rule_b)
end
let(:rule_a) do
Nanoc::RuleDSL::CompilationRule.new(Nanoc::Int::Pattern.from('/foo.*'), :default, proc {})
end
let(:rule_b) do
Nanoc::RuleDSL::CompilationRule.new(Nanoc::Int::Pattern.from('/bar.*'), :default, proc {})
end
it 'is the single rule' do
expect(subject).to contain_exactly(rule_a)
end
end
context 'some rules, multiple matching' do
before do
rules_collection.add_item_compilation_rule(rule_a)
rules_collection.add_item_compilation_rule(rule_b)
end
let(:rule_a) do
Nanoc::RuleDSL::CompilationRule.new(Nanoc::Int::Pattern.from('/foo.*'), :default, proc {})
end
let(:rule_b) do
Nanoc::RuleDSL::CompilationRule.new(Nanoc::Int::Pattern.from('/*.*'), :default, proc {})
end
it 'is all matching rule' do
expect(subject).to contain_exactly(rule_a, rule_b)
end
end
end
describe '#routing_rules_for' do
let(:item) { Nanoc::Int::Item.new('content', {}, '/foo.md') }
let(:rep) { Nanoc::Int::ItemRep.new(item, :default) }
subject { rules_collection.routing_rules_for(rep) }
let(:rules) do
[
# Matching item, matching rep
Nanoc::RuleDSL::RoutingRule.new(
Nanoc::Int::Pattern.from('/foo.*'), :default, proc {}, snapshot_name: :a
),
Nanoc::RuleDSL::RoutingRule.new(
Nanoc::Int::Pattern.from('/foo.*'), :default, proc {}, snapshot_name: :b
),
# Matching item, non-matching rep
Nanoc::RuleDSL::RoutingRule.new(
Nanoc::Int::Pattern.from('/foo.*'), :raw, proc {}, snapshot_name: :a
),
Nanoc::RuleDSL::RoutingRule.new(
Nanoc::Int::Pattern.from('/foo.*'), :raw, proc {}, snapshot_name: :b
),
# Non-matching item, matching rep
Nanoc::RuleDSL::RoutingRule.new(
Nanoc::Int::Pattern.from('/bar.*'), :default, proc {}, snapshot_name: :a
),
Nanoc::RuleDSL::RoutingRule.new(
Nanoc::Int::Pattern.from('/bar.*'), :default, proc {}, snapshot_name: :b
),
# Non-matching item, non-matching rep
Nanoc::RuleDSL::RoutingRule.new(
Nanoc::Int::Pattern.from('/bar.*'), :raw, proc {}, snapshot_name: :a
),
Nanoc::RuleDSL::RoutingRule.new(
Nanoc::Int::Pattern.from('/bar.*'), :raw, proc {}, snapshot_name: :b
),
# Matching item, matching rep, but not the first
Nanoc::RuleDSL::RoutingRule.new(
Nanoc::Int::Pattern.from('/*.*'), :default, proc {}, snapshot_name: :a
),
Nanoc::RuleDSL::RoutingRule.new(
Nanoc::Int::Pattern.from('/*.*'), :default, proc {}, snapshot_name: :b
),
]
end
before do
rules.each do |rule|
rules_collection.add_item_routing_rule(rule)
end
end
it 'returns the first matching rule for every snapshot' do
expect(subject).to eq(
a: rules[0],
b: rules[1],
)
end
end
describe '#filter_for_layout' do
let(:layout) { Nanoc::Int::Layout.new('Some content', {}, '/foo.md') }
subject { rules_collection.filter_for_layout(layout) }
let(:mapping) { {} }
before do
mapping.each_pair do |key, value|
rules_collection.layout_filter_mapping[Nanoc::Int::Pattern.from(key)] = value
end
end
context 'no rules' do
it { is_expected.to be_nil }
end
context 'one non-matching rule' do
let(:mapping) do
{
'/default.*' => [:erb, {}],
}
end
it { is_expected.to be_nil }
end
context 'one matching rule' do
let(:mapping) do
{
'/foo.*' => [:erb, {}],
}
end
it 'is the single one' do
expect(subject).to eq([:erb, {}])
end
end
context 'multiple matching rules' do
let(:mapping) do
{
'/foo.*' => [:erb, {}],
'/*' => [:haml, {}],
}
end
it 'is the first one' do
expect(subject).to eq([:erb, {}])
end
end
end
end
������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������nanoc-4.11.0/nanoc/spec/nanoc/spec_spec.rb����������������������������������������������������������0000664�0000000�0000000�00000002702�13400501750�0020306�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������# frozen_string_literal: true
describe Nanoc::Spec::HelperContext do
let(:helper) do
Module.new {}
end
subject(:ctx) { described_class.new(helper) }
it 'has no items by default' do
# TODO: Add #empty? to item collection view
expect(subject.items.size).to eq(0)
end
it 'has no layouts by default' do
# TODO: Add #empty? to item collection view
expect(subject.layouts.size).to eq(0)
end
describe '#create_item' do
subject { ctx.create_item('foo', {}, '/foo.md') }
it 'creates item' do
expect { subject }
.to change { ctx.items.size }
.from(0).to(1)
end
it 'creates item without reps' do
subject
expect(ctx.items['/foo.md'].reps.size).to eq(0)
end
it 'returns self' do
expect(subject).to eq(ctx)
end
end
describe '#create_layout' do
subject { ctx.create_layout('foo', {}, '/foo.md') }
it 'creates layout' do
expect { subject }
.to change { ctx.layouts.size }
.from(0).to(1)
end
it 'returns self' do
expect(subject).to eq(ctx)
end
end
describe '#create_rep' do
before do
ctx.create_item('foo', {}, '/foo.md')
end
subject { ctx.create_rep(ctx.items['/foo.md'], '/foo.html') }
it 'creates rep' do
expect { subject }
.to change { ctx.items['/foo.md'].reps.size }
.from(0).to(1)
end
it 'returns self' do
expect(subject).to eq(ctx)
end
end
end
��������������������������������������������������������������nanoc-4.11.0/nanoc/spec/regression_filenames_spec.rb������������������������������������������������0000664�0000000�0000000�00000001046�13400501750�0022461�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������# frozen_string_literal: true
describe 'regression tests', chdir: false do
let(:regression_test_filenames) do
Dir['spec/nanoc/regressions/*']
end
let(:regression_test_numbers) do
regression_test_filenames
.map { |fn| File.readlines(fn).find { |l| l =~ /^describe/ }.match(/GH-(\d+)/)[1] }
end
it 'should have the proper filenames' do
regression_test_filenames.zip(regression_test_numbers) do |fn, num|
expect(fn).to match(/gh_#{num}[a-z]*_spec/), "#{fn} has the wrong name in its #define block"
end
end
end
������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������nanoc-4.11.0/nanoc/spec/spec_helper.rb��������������������������������������������������������������0000664�0000000�0000000�00000000213�13400501750�0017530�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������# frozen_string_literal: true
require_relative '../../common/spec/spec_helper_head'
require_relative '../../common/spec/spec_helper_foot'
�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������nanoc-4.11.0/nanoc/test/����������������������������������������������������������������������������0000775�0000000�0000000�00000000000�13400501750�0014743�5����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������nanoc-4.11.0/nanoc/test/base/�����������������������������������������������������������������������0000775�0000000�0000000�00000000000�13400501750�0015655�5����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������nanoc-4.11.0/nanoc/test/base/test_compiler.rb�������������������������������������������������������0000664�0000000�0000000�00000016015�13400501750�0021056�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������# frozen_string_literal: true
require 'helper'
class Nanoc::Int::CompilerTest < Nanoc::TestCase
def test_compile_rep_should_write_proper_snapshots_real
with_site do |_site|
File.write('content/moo.txt', '<%= 1 %> <%%= 2 %> <%%%= 3 %>')
File.write('layouts/default.erb', 'head <%= yield %> foot')
File.open('Rules', 'w') do |io|
io.write "compile '/**/*' do\n"
io.write " filter :erb\n"
io.write " filter :erb\n"
io.write " layout 'default'\n"
io.write " filter :erb\n"
io.write "end\n"
io.write "\n"
io.write "route '/**/*', snapshot: :raw do\n"
io.write " '/moo-raw.txt'\n"
io.write "end\n"
io.write "\n"
io.write "route '/**/*', snapshot: :pre do\n"
io.write " '/moo-pre.txt'\n"
io.write "end\n"
io.write "\n"
io.write "route '/**/*', snapshot: :post do\n"
io.write " '/moo-post.txt'\n"
io.write "end\n"
io.write "\n"
io.write "route '/**/*' do\n"
io.write " '/moo-last.txt'\n"
io.write "end\n"
io.write "\n"
io.write "layout '/**/*', :erb\n"
end
site = Nanoc::Int::SiteLoader.new.new_from_cwd
site.compile
assert File.file?('output/moo-raw.txt')
assert File.file?('output/moo-pre.txt')
assert File.file?('output/moo-post.txt')
assert File.file?('output/moo-last.txt')
assert_equal '<%= 1 %> <%%= 2 %> <%%%= 3 %>', File.read('output/moo-raw.txt')
assert_equal '1 2 <%= 3 %>', File.read('output/moo-pre.txt')
assert_equal 'head 1 2 3 foot', File.read('output/moo-post.txt')
assert_equal 'head 1 2 3 foot', File.read('output/moo-last.txt')
end
end
def test_compile_with_no_reps
with_site do |site|
site.compile
assert Dir['output/*'].empty?
end
end
def test_compile_with_one_rep
with_site do |_site|
File.open('content/index.html', 'w') { |io| io.write('o hello') }
site = Nanoc::Int::SiteLoader.new.new_from_cwd
site.compile
assert Dir['output/*'].size == 1
assert File.file?('output/index.html')
assert File.read('output/index.html') == 'o hello'
end
end
def test_compile_with_two_independent_reps
with_site do |_site|
File.open('content/foo.html', 'w') { |io| io.write('o hai') }
File.open('content/bar.html', 'w') { |io| io.write('o bai') }
site = Nanoc::Int::SiteLoader.new.new_from_cwd
site.compile
assert Dir['output/*'].size == 2
assert File.file?('output/foo/index.html')
assert File.file?('output/bar/index.html')
assert File.read('output/foo/index.html') == 'o hai'
assert File.read('output/bar/index.html') == 'o bai'
end
end
def test_compile_with_two_dependent_reps
with_site(compilation_rule_content: 'filter :erb') do |_site|
File.open('content/foo.html', 'w') do |io|
io.write('<%= @items.find { |i| i.identifier == "/bar/" }.compiled_content %>!!!')
end
File.open('content/bar.html', 'w') do |io|
io.write('manatee')
end
site = Nanoc::Int::SiteLoader.new.new_from_cwd
site.compile
assert Dir['output/*'].size == 2
assert File.file?('output/foo/index.html')
assert File.file?('output/bar/index.html')
assert File.read('output/foo/index.html') == 'manatee!!!'
assert File.read('output/bar/index.html') == 'manatee'
end
end
def test_compile_with_two_mutually_dependent_reps
with_site(compilation_rule_content: 'filter :erb') do |_site|
File.open('content/foo.html', 'w') do |io|
io.write('<%= @items.find { |i| i.identifier == "/bar/" }.compiled_content %>')
end
File.open('content/bar.html', 'w') do |io|
io.write('<%= @items.find { |i| i.identifier == "/foo/" }.compiled_content %>')
end
site = Nanoc::Int::SiteLoader.new.new_from_cwd
assert_raises Nanoc::Int::Errors::DependencyCycle do
site.compile
end
end
end
def test_disallow_routes_not_starting_with_slash
# Create site
Nanoc::CLI.run %w[create_site bar]
FileUtils.cd('bar') do
# Create routes
File.open('Rules', 'w') do |io|
io.write "compile '/**/*' do\n"
io.write " layout 'default'\n"
io.write "end\n"
io.write "\n"
io.write "route '/**/*' do\n"
io.write " 'index.html'\n"
io.write "end\n"
io.write "\n"
io.write "layout '/**/*', :erb\n"
end
# Create site
site = Nanoc::Int::SiteLoader.new.new_from_cwd
error = assert_raises(Nanoc::Error) do
site.compile
end
assert_match(/^The path returned for the.*does not start with a slash. Please ensure that all routing rules return a path that starts with a slash./, error.message)
end
end
def test_include_compiled_content_of_active_item_at_previous_snapshot
with_site do |_site|
# Create item
File.open('content/index.html', 'w') do |io|
io.write('[<%= @item.compiled_content(:snapshot => :aaa) %>]')
end
# Create routes
File.open('Rules', 'w') do |io|
io.write "compile '*' do\n"
io.write " snapshot :aaa\n"
io.write " filter :erb\n"
io.write " filter :erb\n"
io.write "end\n"
io.write "\n"
io.write "route '*' do\n"
io.write " '/index.html'\n"
io.write "end\n"
io.write "\n"
io.write "layout '*', :erb\n"
end
# Compile
site = Nanoc::Int::SiteLoader.new.new_from_cwd
site.compile
# Check
assert_equal '[[[<%= @item.compiled_content(:snapshot => :aaa) %>]]]', File.read('output/index.html')
end
end
def test_mutually_include_compiled_content_at_previous_snapshot
with_site do |_site|
# Create items
File.open('content/a.html', 'w') do |io|
io.write('[<%= @items.find { |i| i.identifier == "/z/" }.compiled_content(:snapshot => :guts) %>]')
end
File.open('content/z.html', 'w') do |io|
io.write('stuff')
end
# Create routes
File.open('Rules', 'w') do |io|
io.write "compile '*' do\n"
io.write " snapshot :guts\n"
io.write " filter :erb\n"
io.write "end\n"
io.write "\n"
io.write "route '*' do\n"
io.write " item.identifier + 'index.html'\n"
io.write "end\n"
io.write "\n"
io.write "layout '*', :erb\n"
end
# Compile
site = Nanoc::Int::SiteLoader.new.new_from_cwd
site.compile
# Check
assert_equal '[stuff]', File.read('output/a/index.html')
assert_equal 'stuff', File.read('output/z/index.html')
end
end
def test_tmp_text_items_are_removed_after_compilation
with_site do |_site|
# Create item
File.open('content/index.html', 'w') do |io|
io.write('stuff')
end
# Compile
site = Nanoc::Int::SiteLoader.new.new_from_cwd
site.compile
# Check
assert Dir['tmp/text_items/*'].empty?
end
end
end
�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������nanoc-4.11.0/nanoc/test/base/test_site.rb�����������������������������������������������������������0000664�0000000�0000000�00000010415�13400501750�0020206�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������# frozen_string_literal: true
require 'helper'
class Nanoc::Int::SiteTest < Nanoc::TestCase
def test_initialize_with_dir_without_config_yaml
assert_raises(Nanoc::Int::ConfigLoader::NoConfigFileFoundError) do
Nanoc::Int::SiteLoader.new.new_from_cwd
end
end
def test_initialize_with_dir_with_config_yaml
File.open('config.yaml', 'w') { |io| io.write('output_dir: public_html') }
site = Nanoc::Int::SiteLoader.new.new_from_cwd
assert_equal Dir.getwd + '/public_html', site.config.output_dir
end
def test_initialize_with_dir_with_nanoc_yaml
File.open('nanoc.yaml', 'w') { |io| io.write('output_dir: public_html') }
site = Nanoc::Int::SiteLoader.new.new_from_cwd
assert_equal Dir.getwd + '/public_html', site.config.output_dir
end
def test_initialize_with_incomplete_data_source_config
File.open('nanoc.yaml', 'w') { |io| io.write('data_sources: [{ items_root: "/bar/" }]') }
site = Nanoc::Int::SiteLoader.new.new_from_cwd
assert_equal('filesystem', site.config[:data_sources][0][:type])
assert_equal('/bar/', site.config[:data_sources][0][:items_root])
assert_equal('/', site.config[:data_sources][0][:layouts_root])
assert_equal({}, site.config[:data_sources][0][:config])
end
def test_initialize_with_existing_parent_config_file
File.open('nanoc.yaml', 'w') do |io|
io.write <<~EOF
output_dir: public_html
parent_config_file: foo/foo.yaml
EOF
end
FileUtils.mkdir_p('foo')
FileUtils.cd('foo') do
File.open('foo.yaml', 'w') do |io|
io.write <<~EOF
parent_config_file: ../bar/bar.yaml
EOF
end
end
FileUtils.mkdir_p('bar')
FileUtils.cd('bar') do
File.open('bar.yaml', 'w') do |io|
io.write <<~EOF
enable_output_diff: true
foo: bar
output_dir: output
EOF
end
end
site = Nanoc::Int::SiteLoader.new.new_from_cwd
assert_nil site.config[:parent_config_file]
assert site.config[:enable_output_diff]
assert_equal 'bar', site.config[:foo]
assert_equal Dir.getwd + '/public_html', site.config.output_dir
end
def test_initialize_with_missing_parent_config_file
File.open('nanoc.yaml', 'w') do |io|
io.write <<~EOF
parent_config_file: foo/foo.yaml
EOF
end
assert_raises(Nanoc::Int::ConfigLoader::NoParentConfigFileFoundError) do
Nanoc::Int::SiteLoader.new.new_from_cwd
end
end
def test_initialize_with_parent_config_file_cycle
File.open('nanoc.yaml', 'w') do |io|
io.write <<~EOF
parent_config_file: foo/foo.yaml
EOF
end
FileUtils.mkdir_p('foo')
FileUtils.cd('foo') do
File.open('foo.yaml', 'w') do |io|
io.write <<~EOF
parent_config_file: ../nanoc.yaml
EOF
end
end
assert_raises(Nanoc::Int::ConfigLoader::CyclicalConfigFileError) do
Nanoc::Int::SiteLoader.new.new_from_cwd
end
end
def test_identifier_classes
Nanoc::CLI.run %w[create_site bar]
FileUtils.cd('bar') do
FileUtils.mkdir_p('content')
FileUtils.mkdir_p('layouts')
File.open('content/foo_bar.md', 'w') { |io| io << 'asdf' }
File.open('layouts/detail.erb', 'w') { |io| io << 'asdf' }
site = Nanoc::Int::SiteLoader.new.new_from_cwd
site.items.each do |item|
assert_equal Nanoc::Identifier, item.identifier.class
end
site.layouts.each do |layout|
assert_equal Nanoc::Identifier, layout.identifier.class
end
end
end
def test_multiple_items_with_same_identifier
with_site do
File.open('content/sam.html', 'w') { |io| io.write('I am Sam!') }
FileUtils.mkdir_p('content/sam')
File.open('content/sam/index.html', 'w') { |io| io.write('I am Sam, too!') }
assert_raises(Nanoc::Int::Errors::DuplicateIdentifier) do
Nanoc::Int::SiteLoader.new.new_from_cwd
end
end
end
def test_multiple_layouts_with_same_identifier
with_site do
File.open('layouts/sam.html', 'w') { |io| io.write('I am Sam!') }
FileUtils.mkdir_p('layouts/sam')
File.open('layouts/sam/index.html', 'w') { |io| io.write('I am Sam, too!') }
assert_raises(Nanoc::Int::Errors::DuplicateIdentifier) do
Nanoc::Int::SiteLoader.new.new_from_cwd
end
end
end
end
���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������nanoc-4.11.0/nanoc/test/checking/�������������������������������������������������������������������0000775�0000000�0000000�00000000000�13400501750�0016516�5����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������nanoc-4.11.0/nanoc/test/checking/checks/������������������������������������������������������������0000775�0000000�0000000�00000000000�13400501750�0017756�5����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������nanoc-4.11.0/nanoc/test/checking/checks/test_css.rb�������������������������������������������������0000664�0000000�0000000�00000003607�13400501750�0022140�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������# frozen_string_literal: true
require 'helper'
class Nanoc::Checking::Checks::CSSTest < Nanoc::TestCase
def test_run_ok
VCR.use_cassette('css_run_ok') do
with_site do |site|
# Create files
FileUtils.mkdir_p('output')
File.open('output/blah.html', 'w') { |io| io.write('<h1>Hi!</h1>') }
File.open('output/style.css', 'w') { |io| io.write('h1 { color: red; }') }
# Run check
check = Nanoc::Checking::Checks::CSS.create(site)
check.run
# Check
assert check.issues.empty?
end
end
end
def test_run_error
VCR.use_cassette('css_run_error') do
with_site do |site|
# Create files
FileUtils.mkdir_p('output')
File.open('output/blah.html', 'w') { |io| io.write('<h1>Hi!</h1>') }
File.open('output/style.css', 'w') { |io| io.write('h1 { coxlor: rxed; }') }
# Run check
check = Nanoc::Checking::Checks::CSS.create(site)
check.run
# Check
refute check.issues.empty?
assert_equal 1, check.issues.size
assert_equal(
"line 1: Property “coxlor” doesn't exist. The closest matching property name is “color”: h1 { coxlor: rxed; }",
check.issues.to_a[0].description,
)
end
end
end
def test_run_parse_error
VCR.use_cassette('css_run_parse_error') do
with_site do |site|
# Create files
FileUtils.mkdir_p('output')
File.open('output/blah.html', 'w') { |io| io.write('<h1>Hi!</h1>') }
File.open('output/style.css', 'w') { |io| io.write('h1 { ; {') }
# Run check
check = Nanoc::Checking::Checks::CSS.create(site)
check.run
# Check
refute check.issues.empty?
assert_equal 1, check.issues.size
assert_equal 'line 1: Parse Error: h1 { ; {', check.issues.to_a[0].description
end
end
end
end
�������������������������������������������������������������������������������������������������������������������������nanoc-4.11.0/nanoc/test/checking/checks/test_external_links.rb��������������������������������������0000664�0000000�0000000�00000005726�13400501750�0024376�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������# frozen_string_literal: true
require 'helper'
class Nanoc::Checking::Checks::ExternalLinksTest < Nanoc::TestCase
def test_run
with_site do |site|
# Create files
FileUtils.mkdir_p('output')
File.open('output/foo.txt', 'w') { |io| io.write('<a href="http://example.com/404">broken</a>') }
File.open('output/bar.html', 'w') { |io| io.write('<a href="http://example.com/">not broken</a>') }
# Create check
check = Nanoc::Checking::Checks::ExternalLinks.create(site)
def check.request_url_once(url)
Net::HTTPResponse.new('1.1', url.path == '/' ? '200' : '404', 'okay')
end
check.run
# Test
assert check.issues.empty?
end
end
def test_valid_by_path
with_site do |site|
# Create check
check = Nanoc::Checking::Checks::ExternalLinks.create(site)
def check.request_url_once(url)
Net::HTTPResponse.new('1.1', url.path == '/200' ? '200' : '404', 'okay')
end
# Test
assert_nil check.validate('http://127.0.0.1:9204/200')
assert_nil check.validate('foo://example.com/')
refute_nil check.validate('http://127.0.0.1:9204">')
end
end
def test_valid_by_query
with_site do |site|
# Create check
check = Nanoc::Checking::Checks::ExternalLinks.create(site)
def check.request_url_once(url)
Net::HTTPResponse.new('1.1', url.query == 'status=200' ? '200' : '404', 'okay')
end
# Test
assert_nil check.validate('http://example.com/?status=200')
refute_nil check.validate('http://example.com/?status=404')
end
end
def test_path_for_url
with_site do |site|
check = Nanoc::Checking::Checks::ExternalLinks.create(site)
assert_equal '/', check.send(:path_for_url, URI.parse('http://example.com'))
assert_equal '/', check.send(:path_for_url, URI.parse('http://example.com/'))
assert_equal '/?foo=bar', check.send(:path_for_url, URI.parse('http://example.com?foo=bar'))
assert_equal '/?foo=bar', check.send(:path_for_url, URI.parse('http://example.com/?foo=bar'))
assert_equal '/meow?foo=bar', check.send(:path_for_url, URI.parse('http://example.com/meow?foo=bar'))
end
end
def test_excluded
with_site do |site|
site.config.update(checks: { external_links: { exclude: ['^http://excluded.com$'] } })
check = Nanoc::Checking::Checks::ExternalLinks.create(site)
assert check.send(:excluded?, 'http://excluded.com')
refute check.send(:excluded?, 'http://excluded.com/notexcluded')
refute check.send(:excluded?, 'http://notexcluded.com')
end
end
def test_excluded_file
with_site do |site|
site.config.update(checks: { external_links: { exclude_files: ['blog/page'] } })
check = Nanoc::Checking::Checks::ExternalLinks.create(site)
assert check.send(:excluded_file?, 'output/blog/page1/index.html')
refute check.send(:excluded_file?, 'output/blog/pag1/index.html')
end
end
end
������������������������������������������nanoc-4.11.0/nanoc/test/checking/checks/test_html.rb������������������������������������������������0000664�0000000�0000000�00000003231�13400501750�0022305�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������# frozen_string_literal: true
require 'helper'
class Nanoc::Checking::Checks::HTMLTest < Nanoc::TestCase
def test_run_ok
require 'w3c_validators'
VCR.use_cassette('html_run_ok') do
with_site do |site|
# Create files
FileUtils.mkdir_p('output')
File.open('output/blah.html', 'w') { |io| io.write('<!DOCTYPE html><html><head><meta charset="utf-8"><title>Hello Hi!
') }
File.open('output/style.css', 'w') { |io| io.write('h1 { coxlor: rxed; }') }
# Run check
check = Nanoc::Checking::Checks::HTML.create(site)
check.run
# Check
assert check.issues.empty?
end
end
end
def test_run_error
VCR.use_cassette('html_run_error') do
with_site do |site|
# Create files
FileUtils.mkdir_p('output')
File.open('output/blah.html', 'w') { |io| io.write('Hi!
') }
File.open('output/style.css', 'w') { |io| io.write('h1 { coxlor: rxed; }') }
# Run check
check = Nanoc::Checking::Checks::HTML.create(site)
check.run
# Check
refute check.issues.empty?
assert_equal 3, check.issues.size
assert_equal 'line 1: Start tag seen without seeing a doctype first. Expected e.g. “”.: Hi!
', check.issues.to_a[0].description
assert_equal 'line 1: Element “head” is missing a required instance of child element “title”.: Hi!
', check.issues.to_a[1].description
assert_equal 'line 1: End tag “h1” seen, but there were open elements.: Hi!
', check.issues.to_a[2].description
end
end
end
end
nanoc-4.11.0/nanoc/test/checking/checks/test_internal_links.rb000066400000000000000000000073061340050175000243640ustar00rootroot00000000000000# frozen_string_literal: true
require 'helper'
class Nanoc::Checking::Checks::InternalLinksTest < Nanoc::TestCase
def test_run
with_site do |site|
# Create files
FileUtils.mkdir_p('output')
FileUtils.mkdir_p('output/stuff')
File.open('output/foo.txt', 'w') { |io| io.write('broken') }
File.open('output/bar.html', 'w') { |io| io.write('not broken') }
# Create check
check = Nanoc::Checking::Checks::InternalLinks.create(site)
check.run
# Test
assert check.issues.empty?
end
end
def test_resource_uris
with_site do |site|
# Create files
FileUtils.mkdir_p('output')
File.open('output/bar.html', 'w') { |io| io.write('') }
# Create check
check = Nanoc::Checking::Checks::InternalLinks.create(site)
check.run
# Test
assert check.issues.size == 1
end
end
def test_valid?
with_site do |site|
# Create files
FileUtils.mkdir_p('output')
FileUtils.mkdir_p('output/stuff')
File.open('output/origin', 'w') { |io| io.write('hi') }
File.open('output/foo', 'w') { |io| io.write('hi') }
File.open('output/stuff/blah', 'w') { |io| io.write('hi') }
# Create check
check = Nanoc::Checking::Checks::InternalLinks.create(site)
# Test
assert check.send(:valid?, 'foo', 'output/origin')
assert check.send(:valid?, 'origin', 'output/origin')
assert check.send(:valid?, 'stuff/blah', 'output/origin')
assert check.send(:valid?, '/foo', 'output/origin')
assert check.send(:valid?, '/origin', 'output/origin')
assert check.send(:valid?, '/stuff/blah', 'output/origin')
end
end
def test_remove_query_string
with_site do |site|
FileUtils.mkdir_p('output/stuff')
File.open('output/stuff/right', 'w') { |io| io.write('hi') }
check = Nanoc::Checking::Checks::InternalLinks.create(site)
assert check.send(:valid?, 'stuff/right?foo=123', 'output/origin')
refute check.send(:valid?, 'stuff/wrong?foo=123', 'output/origin')
end
end
def test_exclude
with_site do |site|
site.config.update(checks: { internal_links: { exclude: ['^/excluded\d+'] } })
check = Nanoc::Checking::Checks::InternalLinks.create(site)
assert check.send(:valid?, '/excluded1', 'output/origin')
assert check.send(:valid?, '/excluded2', 'output/origin')
assert !check.send(:valid?, '/excluded_not', 'output/origin')
end
end
def test_exclude_targets
with_site do |site|
site.config.update(checks: { internal_links: { exclude_targets: ['^/excluded\d+'] } })
check = Nanoc::Checking::Checks::InternalLinks.create(site)
assert check.send(:valid?, '/excluded1', 'output/origin')
assert check.send(:valid?, '/excluded2', 'output/origin')
assert !check.send(:valid?, '/excluded_not', 'output/origin')
end
end
def test_exclude_origins
with_site do |site|
site.config.update(checks: { internal_links: { exclude_origins: ['^/excluded'] } })
check = Nanoc::Checking::Checks::InternalLinks.create(site)
assert check.send(:valid?, '/foo', 'output/excluded')
assert !check.send(:valid?, '/foo', 'output/not_excluded')
end
end
def test_unescape_url
with_site do |site|
FileUtils.mkdir_p('output/stuff')
File.open('output/stuff/right foo', 'w') { |io| io.write('hi') }
check = Nanoc::Checking::Checks::InternalLinks.create(site)
assert check.send(:valid?, 'stuff/right%20foo', 'output/origin')
refute check.send(:valid?, 'stuff/wrong%20foo', 'output/origin')
end
end
end
nanoc-4.11.0/nanoc/test/checking/checks/test_mixed_content.rb000066400000000000000000000145021340050175000242040ustar00rootroot00000000000000# frozen_string_literal: true
require 'helper'
class Nanoc::Checking::Checks::MixedContentTest < Nanoc::TestCase
def create_output_file(name, lines)
FileUtils.mkdir_p('output')
File.open('output/' + name, 'w') do |io|
io.write(lines.join('\n'))
end
end
def assert_include(haystack, needle)
assert haystack.include?(needle), "Expected to find '#{needle}' in #{haystack}"
end
def test_https_content
with_site do |site|
create_output_file('foo.html', [
'
',
'
',
'',
'',
'',
'',
'',
'',
])
check = Nanoc::Checking::Checks::MixedContent.create(site)
check.run
assert_empty check.issues
end
end
def test_root_relative_content
with_site do |site|
create_output_file('foo.html', [
'
',
'',
'',
'',
'',
'',
'',
])
check = Nanoc::Checking::Checks::MixedContent.create(site)
check.run
assert_empty check.issues
end
end
def test_protocol_relative_content
with_site do |site|
create_output_file('foo.html', [
'
',
'',
'',
'',
'',
'',
'',
])
check = Nanoc::Checking::Checks::MixedContent.create(site)
check.run
assert_empty check.issues
end
end
def test_document_relative_content
with_site do |site|
create_output_file('foo.html', [
'
',
'',
'',
'',
'',
'',
'',
])
check = Nanoc::Checking::Checks::MixedContent.create(site)
check.run
assert_empty check.issues
end
end
def test_query_relative_content
with_site do |site|
create_output_file('foo.html', [
'
',
'',
'',
'',
'',
'',
'',
])
check = Nanoc::Checking::Checks::MixedContent.create(site)
check.run
assert_empty check.issues
end
end
def test_fragment_relative_content
with_site do |site|
create_output_file('foo.html', [
'
',
'',
'',
'',
'',
'',
'',
])
check = Nanoc::Checking::Checks::MixedContent.create(site)
check.run
assert_empty check.issues
end
end
def test_http_content
with_site do |site|
create_output_file('foo.html', [
'
',
'
',
'',
'',
'',
'',
'',
'',
])
check = Nanoc::Checking::Checks::MixedContent.create(site)
check.run
issues = check.issues.to_a
assert_equal 8, issues.count
descriptions = issues.map(&:description)
issues.each do |issue|
assert_equal 'output/foo.html', issue.subject
end
# The order of the reported issues is not important, so use this class's
# `assert_include` helper to avoid asserting those details
assert_include descriptions, 'mixed content include: http://nanoc.ws/logo.png'
assert_include descriptions, 'mixed content include: HTTP://nanoc.ws/logo.png'
assert_include descriptions, 'mixed content include: http://nanoc.ws/style.css'
assert_include descriptions, 'mixed content include: http://nanoc.ws/app.js'
assert_include descriptions, 'mixed content include: http://nanoc.ws/process.cgi'
assert_include descriptions, 'mixed content include: http://nanoc.ws/preview.html'
assert_include descriptions, 'mixed content include: http://nanoc.ws/theme-song.flac'
assert_include descriptions, 'mixed content include: http://nanoc.ws/screencast.mkv'
end
end
def test_inert_content
with_site do |site|
create_output_file('foo.html', [
'The homepage',
'Content',
'',
'
',
'',
'',
'',
'',
'',
'',
'http://nanoc.ws/harmless-text
',
])
check = Nanoc::Checking::Checks::MixedContent.create(site)
check.run
assert_empty check.issues
end
end
end
nanoc-4.11.0/nanoc/test/checking/checks/test_stale.rb000066400000000000000000000040701340050175000224530ustar00rootroot00000000000000# frozen_string_literal: true
require 'helper'
class Nanoc::Checking::Checks::StaleTest < Nanoc::TestCase
def check_class
Nanoc::Checking::Checks::Stale
end
def calc_issues
site = Nanoc::Int::SiteLoader.new.new_from_cwd
runner = Nanoc::Checking::Runner.new(site)
runner.send(:run_checks, [check_class])
end
def test_run_ok
with_site do |_site|
assert Dir['content/*'].empty?
assert Dir['output/*'].empty?
# Empty
FileUtils.mkdir_p('output')
assert calc_issues.empty?
# One OK file
File.open('content/index.html', 'w') { |io| io.write('stuff') }
File.open('output/index.html', 'w') { |io| io.write('stuff') }
assert calc_issues.empty?
end
end
def test_run_error
with_site do |_site|
assert Dir['content/*'].empty?
assert Dir['output/*'].empty?
File.open('content/index.html', 'w') { |io| io.write('stuff') }
File.open('output/WRONG.html', 'w') { |io| io.write('stuff') }
assert_equal 1, calc_issues.count
issue = calc_issues.to_a[0]
assert_equal 'file without matching item', issue.description
assert_equal 'output/WRONG.html', issue.subject
end
end
def test_run_excluded
with_site do |_site|
assert Dir['content/*'].empty?
assert Dir['output/*'].empty?
File.open('nanoc.yaml', 'w') { |io| io.write "string_pattern_type: legacy\nprune:\n exclude: [ 'excluded.html' ]" }
File.open('content/index.html', 'w') { |io| io.write('stuff') }
File.open('output/excluded.html', 'w') { |io| io.write('stuff') }
assert calc_issues.empty?
end
end
def test_run_excluded_with_broken_config
with_site do |_site|
assert Dir['content/*'].empty?
assert Dir['output/*'].empty?
File.open('nanoc.yaml', 'w') { |io| io.write "string_pattern_type: legacy\nprune:\n blah: meh" }
File.open('content/index.html', 'w') { |io| io.write('stuff') }
File.open('output/excluded.html', 'w') { |io| io.write('stuff') }
assert_raises(JsonSchema::Error) { calc_issues }
end
end
end
nanoc-4.11.0/nanoc/test/checking/test_check.rb000066400000000000000000000011171340050175000211570ustar00rootroot00000000000000# frozen_string_literal: true
require 'helper'
class Nanoc::Checking::CheckTest < Nanoc::TestCase
def test_output_filenames
with_site do |site|
File.open('output/foo.html', 'w') { |io| io.write 'hello' }
check = Nanoc::Checking::Check.create(site)
assert_equal [Dir.getwd + '/output/foo.html'], check.output_filenames
end
end
def test_no_output_dir
with_site do |site|
site.config[:output_dir] = 'non-existent'
assert_raises Nanoc::Checking::OutputDirNotFoundError do
Nanoc::Checking::Check.create(site)
end
end
end
end
nanoc-4.11.0/nanoc/test/checking/test_dsl.rb000066400000000000000000000016751340050175000206750ustar00rootroot00000000000000# frozen_string_literal: true
require 'helper'
class Nanoc::Checking::DSLTest < Nanoc::TestCase
def test_from_file
with_site do |_site|
File.open('Checks', 'w') { |io| io.write("check :foo do\n\nend\ndeploy_check :bar\n") }
enabled_checks = []
Nanoc::Checking::DSL.from_file('Checks', enabled_checks: enabled_checks)
refute Nanoc::Checking::Check.named(:foo).nil?
assert_equal [:bar], enabled_checks
end
end
def test_has_base_path
with_site do |_site|
File.write('stuff.rb', '$greeting = "hello"')
File.write('Checks', 'require "./stuff"')
Nanoc::Checking::DSL.from_file('Checks', enabled_checks: [])
assert_equal 'hello', $greeting
end
end
def test_has_absolute_path
with_site do |_site|
File.write('Checks', '$stuff = __FILE__')
Nanoc::Checking::DSL.from_file('Checks', enabled_checks: [])
assert(Pathname.new($stuff).absolute?)
end
end
end
nanoc-4.11.0/nanoc/test/checking/test_runner.rb000066400000000000000000000021351340050175000214140ustar00rootroot00000000000000# frozen_string_literal: true
require 'helper'
class Nanoc::Checking::RunnerTest < Nanoc::TestCase
def test_run_specific
with_site do |site|
File.open('output/blah', 'w') { |io| io.write('I am stale! Haha!') }
runner = Nanoc::Checking::Runner.new(site)
runner.run_specific(%w[stale])
end
end
def test_run_specific_custom
with_site do |site|
File.open('Checks', 'w') do |io|
io.write('check :my_foo_check do ; puts "I AM FOO!" ; end')
end
runner = Nanoc::Checking::Runner.new(site)
ios = capturing_stdio do
runner.run_specific(%w[my_foo_check])
end
assert ios[:stdout].include?('I AM FOO!')
end
end
def test_list_checks
with_site do |site|
File.open('Checks', 'w') do |io|
io.write('check :my_foo_check do ; end')
end
runner = Nanoc::Checking::Runner.new(site)
ios = capturing_stdio do
runner.list_checks
end
assert ios[:stdout].include?('my_foo_check')
assert ios[:stdout].include?('internal_links')
assert ios[:stderr].empty?
end
end
end
nanoc-4.11.0/nanoc/test/cli/000077500000000000000000000000001340050175000155125ustar00rootroot00000000000000nanoc-4.11.0/nanoc/test/cli/commands/000077500000000000000000000000001340050175000173135ustar00rootroot00000000000000nanoc-4.11.0/nanoc/test/cli/commands/test_check.rb000066400000000000000000000007261340050175000217610ustar00rootroot00000000000000# frozen_string_literal: true
require 'helper'
class Nanoc::CLI::Commands::CheckTest < Nanoc::TestCase
def test_check_stale
with_site do |_site|
FileUtils.mkdir_p('output')
# Should not raise now
Nanoc::CLI.run %w[check stale]
# Should raise now
File.open('output/blah.html', 'w') { |io| io.write 'moo' }
assert_raises Nanoc::Int::Errors::GenericTrivial do
Nanoc::CLI.run %w[check stale]
end
end
end
end
nanoc-4.11.0/nanoc/test/cli/commands/test_compile.rb000066400000000000000000000136001340050175000223270ustar00rootroot00000000000000# frozen_string_literal: true
require 'helper'
class Nanoc::CLI::Commands::CompileTest < Nanoc::TestCase
def test_profiling_information
with_site do |_site|
File.open('content/foo.md', 'w') { |io| io << 'asdf' }
File.open('content/bar.md', 'w') { |io| io << 'asdf' }
File.open('content/baz.md', 'w') { |io| io << 'asdf' }
File.open('Rules', 'w') do |io|
io.write "compile '*' do\n"
io.write " filter :erb\n"
io.write "end\n"
io.write "\n"
io.write "route '*' do\n"
io.write " if item.binary?\n"
io.write " item.identifier.chop + '.' + item[:extension]\n"
io.write " else\n"
io.write " item.identifier + 'index.html'\n"
io.write " end\n"
io.write "end\n"
io.write "\n"
io.write "layout '*', :erb\n"
end
Nanoc::CLI.run %w[compile --verbose]
end
end
def test_auto_prune
with_site do |_site|
File.open('content/foo.md', 'w') { |io| io << 'asdf' }
File.open('content/bar.md', 'w') { |io| io << 'asdf' }
File.open('content/baz.md', 'w') { |io| io << 'asdf' }
File.open('Rules', 'w') do |io|
io.write "compile '*' do\n"
io.write " filter :erb\n"
io.write "end\n"
io.write "\n"
io.write "route '*' do\n"
io.write " if item.binary?\n"
io.write " item.identifier.chop + '.' + item[:extension]\n"
io.write " else\n"
io.write " item.identifier + 'index.html'\n"
io.write " end\n"
io.write "end\n"
io.write "\n"
io.write "layout '*', :erb\n"
end
File.open('nanoc.yaml', 'w') do |io|
io.write "string_pattern_type: legacy\n"
io.write "prune:\n"
io.write " auto_prune: false\n"
end
File.open('output/stray.html', 'w') do |io|
io.write 'I am a stray file and I am about to be deleted!'
end
assert File.file?('output/stray.html')
Nanoc::CLI.run %w[compile]
assert File.file?('output/stray.html')
File.open('nanoc.yaml', 'w') do |io|
io.write "string_pattern_type: legacy\n"
io.write "prune:\n"
io.write " auto_prune: true\n"
end
assert File.file?('output/stray.html')
Nanoc::CLI.run %w[compile]
refute File.file?('output/stray.html')
end
end
def test_auto_prune_with_exclude
with_site do |_site|
File.open('content/foo.md', 'w') { |io| io << 'asdf' }
File.open('content/bar.md', 'w') { |io| io << 'asdf' }
File.open('content/baz.md', 'w') { |io| io << 'asdf' }
File.open('Rules', 'w') do |io|
io.write "compile '*' do\n"
io.write " filter :erb\n"
io.write "end\n"
io.write "\n"
io.write "route '*' do\n"
io.write " if item.binary?\n"
io.write " item.identifier.chop + '.' + item[:extension]\n"
io.write " else\n"
io.write " item.identifier + 'index.html'\n"
io.write " end\n"
io.write "end\n"
io.write "\n"
io.write "layout '*', :erb\n"
end
Dir.mkdir('output/excluded_dir')
File.open('nanoc.yaml', 'w') do |io|
io.write "string_pattern_type: legacy\n"
io.write "prune:\n"
io.write " auto_prune: false\n"
end
File.open('output/stray.html', 'w') do |io|
io.write 'I am a stray file and I am about to be deleted!'
end
assert File.file?('output/stray.html')
Nanoc::CLI.run %w[compile]
assert File.file?('output/stray.html')
File.open('nanoc.yaml', 'w') do |io|
io.write "string_pattern_type: legacy\n"
io.write "prune:\n"
io.write " auto_prune: true\n"
io.write " exclude: [ 'excluded_dir' ]\n"
end
assert File.file?('output/stray.html')
Nanoc::CLI.run %w[compile]
refute File.file?('output/stray.html')
assert File.directory?('output/excluded_dir'), 'excluded_dir should still be there'
end
end
def test_file_action_printer_normal
# Create data
item = Nanoc::Int::Item.new('content', {}, '/a')
rep = Nanoc::Int::ItemRep.new(item, :default)
rep.raw_paths[:last] = ['output/foo.txt']
rep.compiled = true
# Listen
listener = new_file_action_printer([rep])
listener.start
Nanoc::Int::NotificationCenter.post(:compilation_started, rep)
Nanoc::Int::NotificationCenter.post(:rep_write_ended, rep, false, rep.raw_path, false, true)
listener.stop
# Check
assert_equal 1, listener.events.size
assert_equal :high, listener.events[0][:level]
assert_equal :update, listener.events[0][:action]
assert_equal 'output/foo.txt', listener.events[0][:path]
assert_in_delta 0.0, listener.events[0][:duration], 1.0
end
def test_file_action_printer_skip
# Create data
item = Nanoc::Int::Item.new('content', {}, '/a')
rep = Nanoc::Int::ItemRep.new(item, :default)
rep.raw_paths[:last] = ['output/foo.txt']
# Listen
listener = new_file_action_printer([rep])
listener.start
Nanoc::Int::NotificationCenter.post(:compilation_started, rep)
listener.stop
# Check
assert_equal 1, listener.events.size
assert_equal :low, listener.events[0][:level]
assert_equal :skip, listener.events[0][:action]
assert_equal 'output/foo.txt', listener.events[0][:path]
assert_nil listener.events[0][:duration]
end
def new_file_action_printer(reps)
# Ensure CLI is loaded
begin
Nanoc::CLI.run(%w[help %])
rescue SystemExit
end
listener = Nanoc::CLI::Commands::CompileListeners::FileActionPrinter.new(reps: reps)
def listener.log(level, action, path, duration)
@events ||= []
@events << {
level: level,
action: action,
path: path,
duration: duration,
}
end
def listener.events
@events
end
listener
end
end
nanoc-4.11.0/nanoc/test/cli/commands/test_create_site.rb000066400000000000000000000065031340050175000231720ustar00rootroot00000000000000# frozen_string_literal: true
require 'helper'
class Nanoc::CLI::Commands::CreateSiteTest < Nanoc::TestCase
def test_create_site_with_existing_name
Nanoc::CLI.run %w[create_site foo]
assert_raises(::Nanoc::Int::Errors::GenericTrivial) do
Nanoc::CLI.run %w[create_site foo]
end
end
def test_can_compile_new_site
Nanoc::CLI.run %w[create_site foo]
FileUtils.cd('foo') do
site = Nanoc::Int::SiteLoader.new.new_from_cwd
site.compile
end
end
def test_can_compile_new_site_in_current_directory
FileUtils.mkdir('foo')
FileUtils.cd('foo') do
Nanoc::CLI.run %w[create_site ./]
site = Nanoc::Int::SiteLoader.new.new_from_cwd
site.compile
end
end
def test_can_compile_new_site_with_binary_items
Nanoc::CLI.run %w[create_site foo]
FileUtils.cd('foo') do
File.open('content/blah', 'w') { |io| io << 'asdf' }
site = Nanoc::Int::SiteLoader.new.new_from_cwd
site.compile
assert File.file?('output/blah')
end
end
def test_can_compile_site_in_nonempty_directory
FileUtils.mkdir('foo')
FileUtils.touch(File.join('foo', 'SomeFile.txt'))
Nanoc::CLI.run %w[create_site foo --force]
FileUtils.cd('foo') do
site = Nanoc::Int::SiteLoader.new.new_from_cwd
site.compile
end
end
def test_compiled_site_output
FileUtils.mkdir('foo')
FileUtils.touch(File.join('foo', 'SomeFile.txt'))
Nanoc::CLI.run %w[create_site foo --force]
FileUtils.cd('foo') do
site = Nanoc::Int::SiteLoader.new.new_from_cwd
site.compile
assert File.file?('output/index.html')
end
end
def test_default_encoding
unless defined?(Encoding)
skip 'No Encoding class'
return
end
original_encoding = Encoding.default_external
Encoding.default_external = 'ISO-8859-1' # ew!
Nanoc::CLI.run %w[create_site foo]
FileUtils.cd('foo') do
# Try with encoding = default encoding = utf-8
File.open('content/index.html', 'w') { |io| io.write('Hello ' + 0xD6.chr + "!\n") }
exception = assert_raises(Nanoc::DataSources::Filesystem::Errors::InvalidEncoding) do
Nanoc::Int::SiteLoader.new.new_from_cwd
end
assert_equal 'Could not read content/index.html because the file is not valid UTF-8.', exception.message
# Try with encoding = specific
File.open('nanoc.yaml', 'w') do |io|
io.write("string_pattern_type: glob\n")
io.write("data_sources:\n")
io.write(" -\n")
io.write(" type: filesystem\n")
io.write(" identifier_type: full\n")
end
site = Nanoc::Int::SiteLoader.new.new_from_cwd
site.compile
end
FileUtils
ensure
Encoding.default_external = original_encoding
end
def test_new_site_has_correct_stylesheets
Nanoc::CLI.run %w[create_site foo]
FileUtils.cd('foo') do
Nanoc::CLI.run %w[compile]
assert File.file?('content/stylesheet.css')
assert_match(/\/stylesheet.css/, File.read('output/index.html'))
end
end
def test_new_site_prunes_by_default
FileUtils.mkdir('foo')
FileUtils.touch(File.join('foo', 'SomeFile.txt'))
Nanoc::CLI.run %w[create_site foo --force]
FileUtils.cd('foo') do
File.write('output/blah.txt', 'stuff')
Nanoc::CLI.run %w[compile]
refute File.file?('output/blah.txt')
end
end
end
nanoc-4.11.0/nanoc/test/cli/commands/test_help.rb000066400000000000000000000002741340050175000216320ustar00rootroot00000000000000# frozen_string_literal: true
require 'helper'
class Nanoc::CLI::Commands::HelpTest < Nanoc::TestCase
def test_run
Nanoc::CLI.run %w[help]
Nanoc::CLI.run %w[help co]
end
end
nanoc-4.11.0/nanoc/test/cli/commands/test_prune.rb000066400000000000000000000121661340050175000220360ustar00rootroot00000000000000# frozen_string_literal: true
require 'helper'
class Nanoc::CLI::Commands::PruneTest < Nanoc::TestCase
def test_run_without_yes
with_site do |_site|
# Set output dir
File.open('nanoc.yaml', 'w') { |io| io.write "output_dir: output2\nstring_pattern_type: legacy\n" }
FileUtils.mkdir_p('output2')
# Create source files
File.open('content/index.html', 'w') { |io| io.write 'stuff' }
# Create output files
File.open('output2/foo.html', 'w') { |io| io.write 'this is a foo.' }
File.open('output2/index.html', 'w') { |io| io.write 'this is a index.' }
assert_raises SystemExit do
Nanoc::CLI.run %w[prune]
end
assert File.file?('output2/index.html')
assert File.file?('output2/foo.html')
end
end
def test_run_with_yes
with_site do |_site|
# Set output dir
File.open('nanoc.yaml', 'w') do |io|
io << 'output_dir: output2' << "\n"
io << 'string_pattern_type: legacy' << "\n"
io << 'data_sources:' << "\n"
io << ' -' << "\n"
io << ' type: filesystem' << "\n"
io << ' identifier_type: legacy' << "\n"
end
FileUtils.mkdir_p('output2')
# Create source files
File.open('content/index.html', 'w') { |io| io.write 'stuff' }
# Create output files
File.open('output2/foo.html', 'w') { |io| io.write 'this is a foo.' }
File.open('output2/index.html', 'w') { |io| io.write 'this is a index.' }
Nanoc::CLI.run %w[prune --yes]
assert File.file?('output2/index.html')
assert !File.file?('output2/foo.html')
end
end
def test_run_with_dry_run
with_site do |_site|
# Set output dir
File.open('nanoc.yaml', 'w') { |io| io.write "string_pattern_type: legacy\noutput_dir: output2" }
FileUtils.mkdir_p('output2')
# Create source files
File.open('content/index.html', 'w') { |io| io.write 'stuff' }
# Create output files
File.open('output2/foo.html', 'w') { |io| io.write 'this is a foo.' }
File.open('output2/index.html', 'w') { |io| io.write 'this is a index.' }
Nanoc::CLI.run %w[prune --dry-run]
assert File.file?('output2/index.html')
assert File.file?('output2/foo.html')
end
end
def test_run_with_exclude
with_site do |_site|
# Set output dir
File.open('nanoc.yaml', 'w') do |io|
io << 'prune:' << "\n"
io << ' exclude: [ "good-dir", "good-file.html" ]' << "\n"
io << 'string_pattern_type: legacy' << "\n"
io << 'data_sources:' << "\n"
io << ' -' << "\n"
io << ' type: filesystem' << "\n"
io << ' identifier_type: legacy' << "\n"
end
FileUtils.mkdir_p('output')
# Create source files
File.open('content/index.html', 'w') { |io| io.write 'stuff' }
# Create output files
FileUtils.mkdir_p('output/good-dir')
FileUtils.mkdir_p('output/bad-dir')
File.open('output/good-file.html', 'w') { |io| io.write 'stuff' }
File.open('output/good-dir/blah', 'w') { |io| io.write 'stuff' }
File.open('output/bad-file.html', 'w') { |io| io.write 'stuff' }
File.open('output/bad-dir/blah', 'w') { |io| io.write 'stuff' }
File.open('output/index.html', 'w') { |io| io.write 'stuff' }
Nanoc::CLI.run %w[prune --yes]
assert File.file?('output/index.html')
assert File.file?('output/good-dir/blah')
assert File.file?('output/good-file.html')
assert !File.file?('output/bad-dir/blah')
assert !File.file?('output/bad-file.html')
end
end
def test_run_with_symlink_to_output_dir
skip_unless_symlinks_supported
if defined?(JRUBY_VERSION)
skip 'JRuby has buggy File.find behavior (see https://github.com/jruby/jruby/issues/1647)'
end
if Nanoc.on_windows?
skip 'Symlinks to output dirs are currently not supported on Windows.'
end
with_site do |_site|
# Set output dir
FileUtils.rm_rf('output')
FileUtils.mkdir_p('output-real')
File.symlink('output-real', 'output')
# Create source files
File.open('content/index.html', 'w') { |io| io.write 'stuff' }
# Create output files
FileUtils.mkdir_p('output-real/some-dir')
File.open('output-real/some-file.html', 'w') { |io| io.write 'stuff' }
File.open('output-real/index.html', 'w') { |io| io.write 'stuff' }
Nanoc::CLI.run %w[prune --yes]
assert File.file?('output-real/index.html')
assert !File.directory?('output-real/some-dir')
assert !File.file?('output-real/some-file.html')
end
end
def test_run_with_nested_empty_dirs
with_site do |_site|
# Set output dir
File.open('nanoc.yaml', 'w') { |io| io.write 'output_dir: output' }
FileUtils.mkdir_p('output')
# Create output files
FileUtils.mkdir_p('output/a/b/c')
File.open('output/a/b/c/index.html', 'w') { |io| io.write 'stuff' }
Nanoc::CLI.run %w[prune --yes]
assert !File.file?('output/a/b/c/index.html')
assert !File.directory?('output/a/b/c')
assert !File.directory?('output/a/b')
assert !File.directory?('output/a')
end
end
end
nanoc-4.11.0/nanoc/test/cli/test_cleaning_stream.rb000066400000000000000000000040061340050175000222310ustar00rootroot00000000000000# frozen_string_literal: true
require 'helper'
class Nanoc::CLI::CleaningStreamTest < Nanoc::TestCase
class Stream
attr_accessor :called_methods
def initialize
@called_methods = []
end
def method_missing(symbol, *_args) # rubocop:disable Style/MethodMissingSuper
@called_methods << symbol
end
def respond_to_missing?(*_args)
true
end
end
def test_forward
methods = %i[write << tty? tty? flush tell print puts string reopen exist? exists? close]
s = Stream.new
cs = Nanoc::CLI::CleaningStream.new(s)
cs.write('aaa')
cs << 'bb'
cs.tty?
cs.isatty
cs.flush
cs.tell
cs.print('cc')
cs.puts('dd')
cs.string
cs.reopen('/dev/null', 'r')
cs.exist?
cs.exists?
cs.close
methods.each do |m|
assert s.called_methods.include?(m), "expected #{m} to be called"
end
end
def test_forward_tty_cached
s = Stream.new
cs = Nanoc::CLI::CleaningStream.new(s)
cs.tty?
cs.isatty
assert_equal [:tty?], s.called_methods
end
def test_works_with_logger
require 'logger'
stream = StringIO.new
cleaning_stream = Nanoc::CLI::CleaningStream.new(stream)
logger = Logger.new(cleaning_stream)
logger.info('Some info')
logger.warn('Something could start going wrong!')
end
def test_broken_pipe
stream = StringIO.new
def stream.write(_str)
raise Errno::EPIPE.new
end
cleaning_stream = Nanoc::CLI::CleaningStream.new(stream)
cleaning_stream.write('lol')
end
def test_non_string
obj = Object.new
def obj.to_s
'Hello… world!'
end
stream = StringIO.new
cleaning_stream = Nanoc::CLI::CleaningStream.new(stream)
cleaning_stream << obj
assert_equal 'Hello… world!', stream.string
end
def test_invalid_string
s = [128].pack('C').force_encoding('UTF-8')
stream = StringIO.new
cleaning_stream = Nanoc::CLI::CleaningStream.new(stream)
cleaning_stream << s
assert_equal "\xef\xbf\xbd", stream.string
end
end
nanoc-4.11.0/nanoc/test/cli/test_cli.rb000066400000000000000000000124141340050175000176470ustar00rootroot00000000000000# frozen_string_literal: true
require 'helper'
class Nanoc::CLITest < Nanoc::TestCase
COMMAND_CODE = <<~EOS
usage '_test [options]'
summary 'meh'
description 'longer meh'
run do |opts, args, cmd|
File.open('_test.out', 'w') { |io| io.write('It works!') }
end
EOS
SUBCOMMAND_CODE = <<~EOS
usage '_sub [options]'
summary 'meh sub'
description 'longer meh sub'
run do |opts, args, cmd|
File.open('_test_sub.out', 'w') { |io| io.write('It works sub!') }
end
EOS
def test_load_custom_commands
Nanoc::CLI.run %w[create_site foo]
FileUtils.cd('foo') do
# Create command
FileUtils.mkdir_p('commands')
File.open('commands/_test.rb', 'w') { |io| io.write(COMMAND_CODE) }
# Run command
begin
Nanoc::CLI.run %w[_test]
rescue SystemExit
assert false, 'Running _test should not cause system exit'
end
# Check
assert File.file?('_test.out')
assert_equal 'It works!', File.read('_test.out')
end
end
def test_load_custom_commands_nested
Nanoc::CLI.run %w[create_site foo]
FileUtils.cd('foo') do
# Create command
FileUtils.mkdir_p('commands')
File.open('commands/_test.rb', 'w') do |io|
io.write(COMMAND_CODE)
end
# Create subcommand
FileUtils.mkdir_p('commands/_test')
File.open('commands/_test/_sub.rb', 'w') do |io|
io.write(SUBCOMMAND_CODE)
end
# Run command
begin
Nanoc::CLI.run %w[_test _sub]
rescue SystemExit
assert false, 'Running _test sub should not cause system exit'
end
# Check
assert File.file?('_test_sub.out')
assert_equal 'It works sub!', File.read('_test_sub.out')
end
end
def test_load_custom_commands_non_default_commands_dirs
Nanoc::CLI.run %w[create_site foo]
FileUtils.cd('foo') do
File.open('nanoc.yaml', 'w') { |io| io.write('commands_dirs: [commands, commands_alt]') }
# Create command
FileUtils.mkdir_p('commands_alt')
File.open('commands_alt/_test.rb', 'w') do |io|
io.write(COMMAND_CODE)
end
# Create subcommand
FileUtils.mkdir_p('commands_alt/_test')
File.open('commands_alt/_test/_sub.rb', 'w') do |io|
io.write(SUBCOMMAND_CODE)
end
# Run command
begin
Nanoc::CLI.run %w[_test _sub]
rescue SystemExit
assert false, 'Running _test sub should not cause system exit'
end
# Check
assert File.file?('_test_sub.out')
assert_equal 'It works sub!', File.read('_test_sub.out')
end
end
def test_load_custom_commands_broken
Nanoc::CLI.run %w[create_site foo]
FileUtils.cd('foo') do
# Create command
FileUtils.mkdir_p('commands')
File.open('commands/_test.rb', 'w') { |io| io.write('raise "meh"') }
# Run command
position_before = $stderr.tell
Nanoc::CLI::ErrorHandler.disable
assert_raises RuntimeError do
Nanoc::CLI.run %w[_test]
end
Nanoc::CLI::ErrorHandler.enable
assert_raises SystemExit do
Nanoc::CLI.run %w[_test]
end
position_after = $stderr.tell
# Check error output
stderr_addition = $stderr.string[position_before, position_after]
assert_match(/commands\/_test.rb/, stderr_addition)
end
end
def test_load_command_at_with_non_utf8_encoding
Encoding.default_external = Encoding::US_ASCII
Nanoc::CLI.load_command_at(root_dir + '/lib/nanoc/cli/commands/create-site.rb')
ensure
Encoding.default_external = Encoding::UTF_8
end
def test_after_setup
$after_setup_success = false
Nanoc::CLI.after_setup do
$after_setup_success = true
end
Nanoc::CLI.setup
assert $after_setup_success
end
def test_enable_utf8_only_on_tty
new_env_diff = {
'LC_ALL' => 'en_US.ISO-8859-1',
'LC_CTYPE' => 'en_US.ISO-8859-1',
'LANG' => 'en_US.ISO-8859-1',
}
with_env_vars(new_env_diff) do
io = StringIO.new
def io.tty?
true
end
refute Nanoc::CLI.enable_utf8?(io)
io = StringIO.new
def io.tty?
false
end
assert Nanoc::CLI.enable_utf8?(io)
end
end
def test_enable_utf8
io = StringIO.new
def io.tty?
true
end
new_env_diff = {
'LC_ALL' => 'en_US.ISO-8859-1',
'LC_CTYPE' => 'en_US.ISO-8859-1',
'LANG' => 'en_US.ISO-8859-1',
}
with_env_vars(new_env_diff) do
refute Nanoc::CLI.enable_utf8?(io)
with_env_vars('LC_ALL' => 'en_US.UTF-8') { assert Nanoc::CLI.enable_utf8?(io) }
with_env_vars('LC_CTYPE' => 'en_US.UTF-8') { assert Nanoc::CLI.enable_utf8?(io) }
with_env_vars('LANG' => 'en_US.UTF-8') { assert Nanoc::CLI.enable_utf8?(io) }
with_env_vars('LC_ALL' => 'en_US.utf-8') { assert Nanoc::CLI.enable_utf8?(io) }
with_env_vars('LC_CTYPE' => 'en_US.utf-8') { assert Nanoc::CLI.enable_utf8?(io) }
with_env_vars('LANG' => 'en_US.utf-8') { assert Nanoc::CLI.enable_utf8?(io) }
with_env_vars('LC_ALL' => 'en_US.utf8') { assert Nanoc::CLI.enable_utf8?(io) }
with_env_vars('LC_CTYPE' => 'en_US.utf8') { assert Nanoc::CLI.enable_utf8?(io) }
with_env_vars('LANG' => 'en_US.utf8') { assert Nanoc::CLI.enable_utf8?(io) }
end
end
end
nanoc-4.11.0/nanoc/test/cli/test_error_handler.rb000066400000000000000000000060621340050175000217300ustar00rootroot00000000000000# frozen_string_literal: true
require 'helper'
class Nanoc::CLI::ErrorHandlerTest < Nanoc::TestCase
def setup
super
@handler = Nanoc::CLI::ErrorHandler.new
end
def test_resolution_for_with_unknown_gem
error = LoadError.new('no such file to load -- afjlrestjlsgrshter')
assert_nil @handler.send(:resolution_for, error)
end
def test_resolution_for_with_known_gem_without_bundler
def @handler.using_bundler?
false
end
error = LoadError.new('no such file to load -- kramdown')
assert_match(/^Install the 'kramdown' gem using `gem install kramdown`./, @handler.send(:resolution_for, error))
end
def test_resolution_for_with_known_gem_with_bundler
def @handler.using_bundler?
true
end
error = LoadError.new('no such file to load -- kramdown')
assert_match(/^1\. Add.*to your Gemfile/, @handler.send(:resolution_for, error))
end
def test_resolution_for_with_not_load_error
error = RuntimeError.new('nuclear meltdown detected')
assert_nil @handler.send(:resolution_for, error)
end
def test_write_stack_trace_verbose
error = new_error(20)
stream = StringIO.new
@handler.send(:write_stack_trace, stream, error, verbose: false)
assert_match(/ lines omitted \(see crash\.log for details\)/, stream.string)
stream = StringIO.new
@handler.send(:write_stack_trace, stream, error, verbose: false)
assert_match(/ lines omitted \(see crash\.log for details\)/, stream.string)
stream = StringIO.new
@handler.send(:write_stack_trace, stream, error, verbose: true)
refute_match(/ lines omitted \(see crash\.log for details\)/, stream.string)
end
def test_write_error_message_wrapped
stream = StringIO.new
@handler.send(:write_error_message, stream, new_wrapped_error(new_error), verbose: true)
refute_match(/CompilationError/, stream.string)
end
def test_write_stack_trace_wrapped
stream = StringIO.new
@handler.send(:write_stack_trace, stream, new_wrapped_error(new_error), verbose: false)
assert_match(/new_error/, stream.string)
end
def test_write_item_rep
stream = StringIO.new
@handler.send(:write_item_rep, stream, new_wrapped_error(new_error), verbose: false)
assert_match(/^Current item: \/about\.md \(:latex representation\)$/, stream.string)
end
def test_resolution_for_wrapped
def @handler.using_bundler?
true
end
error = new_wrapped_error(LoadError.new('no such file to load -- kramdown'))
assert_match(/^1\. Add.*to your Gemfile/, @handler.send(:resolution_for, error))
end
def new_wrapped_error(wrapped)
item = Nanoc::Int::Item.new('asdf', {}, '/about.md')
item_rep = Nanoc::Int::ItemRep.new(item, :latex)
raise Nanoc::Int::Errors::CompilationError.new(wrapped, item_rep)
rescue => e
e
end
def new_error(amount_factor = 1)
backtrace_generator = lambda do |af|
if af.zero?
raise 'finally!'
else
backtrace_generator.call(af - 1)
end
end
begin
backtrace_generator.call(amount_factor)
rescue => e
return e
end
end
end
nanoc-4.11.0/nanoc/test/cli/test_logger.rb000066400000000000000000000001711340050175000203540ustar00rootroot00000000000000# frozen_string_literal: true
require 'helper'
class Nanoc::CLI::LoggerTest < Nanoc::TestCase
def test_stub; end
end
nanoc-4.11.0/nanoc/test/data_sources/000077500000000000000000000000001340050175000174175ustar00rootroot00000000000000nanoc-4.11.0/nanoc/test/data_sources/test_filesystem.rb000066400000000000000000000611221340050175000231710ustar00rootroot00000000000000# frozen_string_literal: true
require 'helper'
class Nanoc::DataSources::FilesystemTest < Nanoc::TestCase
def new_data_source(params = nil)
with_site do |site|
Nanoc::DataSources::Filesystem.new(site.config, nil, nil, params)
end
end
def test_load_objects
# Create data source
data_source = new_data_source
# Create a fake class
klass = Class.new do
attr_reader :stuff
def initialize(*stuff)
@stuff = stuff
end
def ==(other)
@stuff == other.stuff
end
end
# Create sample files
FileUtils.mkdir_p('foo')
FileUtils.mkdir_p('foo/a/b')
File.open('foo/bar.html', 'w') { |io| io.write("---\nnum: 1\n---\ntest 1") }
File.open('foo/b.c.html', 'w') { |io| io.write("---\nnum: 2\n---\ntest 2") }
File.open('foo/a/b/c.html', 'w') { |io| io.write("---\nnum: 3\n---\ntest 3") }
File.open('foo/ugly.html~', 'w') { |io| io.write("---\nnum: 4\n---\ntest 4") }
File.open('foo/ugly.html.orig', 'w') { |io| io.write("---\nnum: 5\n---\ntest 5") }
File.open('foo/ugly.html.rej', 'w') { |io| io.write("---\nnum: 6\n---\ntest 6") }
File.open('foo/ugly.html.bak', 'w') { |io| io.write("---\nnum: 7\n---\ntest 7") }
# Get expected and actual output
expected_out = [
klass.new(
'test 1',
{ 'num' => 1, :filename => 'foo/bar.html', :extension => 'html', mtime: File.mtime('foo/bar.html') },
'/bar/',
),
klass.new(
'test 2',
{ 'num' => 2, :filename => 'foo/b.c.html', :extension => 'c.html', mtime: File.mtime('foo/b.c.html') },
'/b/',
),
klass.new(
'test 3',
{ 'num' => 3, :filename => 'foo/a/b/c.html', :extension => 'html', mtime: File.mtime('foo/a/b/c.html') },
'/a/b/c/',
),
]
actual_out = data_source.send(:load_objects, 'foo', klass).sort_by { |i| i.stuff[0].string }
# Check
(0..expected_out.size - 1).each do |i|
assert_equal expected_out[i].stuff[0], actual_out[i].stuff[0].string, 'content must match'
assert_equal expected_out[i].stuff[2], actual_out[i].stuff[2], 'identifier must match'
['num', :filename, :extension, :mtime].each do |key|
assert_equal expected_out[i].stuff[1][key], actual_out[i].stuff[1][key], "attribute key #{key} must match"
end
end
end
def test_load_objects_with_same_extensions
# Create data source
data_source = new_data_source(identifier_type: 'full')
# Create a fake class
klass = Class.new do
attr_reader :stuff
def initialize(*stuff)
@stuff = stuff
end
def ==(other)
@stuff == other.stuff
end
end
# Create sample files
FileUtils.mkdir_p('foo')
File.open('foo/bar.html', 'w') { |io| io.write("---\nnum: 1\n---\ntest 1") }
File.open('foo/bar.md', 'w') { |io| io.write("---\nnum: 1\n---\ntest 1") }
# Check
actual_out = data_source.send(:load_objects, 'foo', klass)
assert_equal 2, actual_out.size
end
def test_load_binary_objects
# Create data source
data_source = new_data_source
# Create sample files
FileUtils.mkdir_p('foo')
File.open('foo/stuff.dat', 'w') { |io| io.write('random binary data') }
# Load
items = data_source.send(:load_objects, 'foo', Nanoc::Int::Item)
# Check
assert_equal 1, items.size
assert items[0].content.binary?
assert_equal "#{Dir.getwd}/foo/stuff.dat", items[0].content.filename
assert_equal Nanoc::Int::BinaryContent, items[0].content.class
end
def test_load_layouts_with_nil_dir_name
# Create data source
data_source = new_data_source(layouts_dir: nil)
# Create sample files
FileUtils.mkdir_p('layouts')
File.write('layouts/stuff.txt', 'blah blah')
# Load
layouts = data_source.layouts
# Check
assert_empty(layouts)
end
def test_load_binary_layouts
# Create data source
data_source = new_data_source
# Create sample files
FileUtils.mkdir_p('foo')
File.open('foo/stuff.dat', 'w') { |io| io.write('random binary data') }
# Load
assert_raises(Nanoc::DataSources::Filesystem::Errors::BinaryLayout) do
data_source.send(:load_objects, 'foo', Nanoc::Int::Layout)
end
end
def test_identifier_for_filename_with_full_style_identifier
# Create data source
data_source = new_data_source(identifier_type: 'full')
# Get input and expected output
expected = {
'/foo' => Nanoc::Identifier.new('/foo', type: :full),
'/foo.html' => Nanoc::Identifier.new('/foo.html', type: :full),
'/foo/index.html' => Nanoc::Identifier.new('/foo/index.html', type: :full),
'/foo.html.erb' => Nanoc::Identifier.new('/foo.html.erb', type: :full),
}
# Check
expected.each_pair do |input, expected_output|
actual_output = data_source.send(:identifier_for_filename, input)
assert_equal(
expected_output, actual_output,
"identifier_for_filename(#{input.inspect}) should equal #{expected_output.inspect}, not #{actual_output.inspect}"
)
end
end
def test_identifier_for_filename_allowing_periods_in_identifiers
# Create data source
data_source = new_data_source(allow_periods_in_identifiers: true)
# Get input and expected output
expected = {
'/foo' => '/foo/',
'/foo.html' => '/foo/',
'/foo/index.html' => '/foo/',
'/foo.entry.html' => '/foo.entry/',
}
# Check
expected.each_pair do |input, expected_output|
actual_output = data_source.send(:identifier_for_filename, input)
assert_equal(
expected_output, actual_output,
"identifier_for_filename(#{input.inspect}) should equal #{expected_output.inspect}, not #{actual_output.inspect}"
)
end
end
def test_identifier_for_filename_disallowing_periods_in_identifiers
# Create data source
data_source = new_data_source
# Get input and expected output
expected = {
'/foo' => '/foo/',
'/foo.html' => '/foo/',
'/foo/index.html' => '/foo/',
'/foo.html.erb' => '/foo/',
}
# Check
expected.each_pair do |input, expected_output|
actual_output = data_source.send(:identifier_for_filename, input)
assert_equal(
expected_output, actual_output,
"identifier_for_filename(#{input.inspect}) should equal #{expected_output.inspect}, not #{actual_output.inspect}"
)
end
end
def test_identifier_for_filename_with_subfilename_allowing_periods_in_identifiers
expectations = {
'foo/bar.yaml' => '/foo/bar/',
'foo/quxbar.yaml' => '/foo/quxbar/',
'foo/barqux.yaml' => '/foo/barqux/',
'foo/quxbarqux.yaml' => '/foo/quxbarqux/',
'foo/qux.bar.yaml' => '/foo/qux.bar/',
'foo/bar.qux.yaml' => '/foo/bar.qux/',
'foo/qux.bar.qux.yaml' => '/foo/qux.bar.qux/',
'foo/index.yaml' => '/foo/',
'index.yaml' => '/',
'foo/blah_index.yaml' => '/foo/blah_index/',
}
data_source = new_data_source(allow_periods_in_identifiers: true)
expectations.each_pair do |meta_filename, expected_identifier|
content_filename = meta_filename.sub(/yaml$/, 'html')
[meta_filename, content_filename].each do |filename|
assert_equal(
expected_identifier,
data_source.instance_eval { identifier_for_filename(filename) },
)
end
end
end
def test_identifier_for_filename_with_subfilename_disallowing_periods_in_identifiers
expectations = {
'foo/bar.yaml' => '/foo/bar/',
'foo/quxbar.yaml' => '/foo/quxbar/',
'foo/barqux.yaml' => '/foo/barqux/',
'foo/quxbarqux.yaml' => '/foo/quxbarqux/',
'foo/qux.bar.yaml' => '/foo/qux/',
'foo/bar.qux.yaml' => '/foo/bar/',
'foo/qux.bar.qux.yaml' => '/foo/qux/',
'foo/index.yaml' => '/foo/',
'index.yaml' => '/',
'foo/blah_index.yaml' => '/foo/blah_index/',
}
data_source = new_data_source
expectations.each_pair do |meta_filename, expected_identifier|
content_filename = meta_filename.sub(/yaml$/, 'html')
[meta_filename, content_filename].each do |filename|
assert_equal(
expected_identifier,
data_source.instance_eval { identifier_for_filename(filename) },
)
end
end
end
def test_identifier_for_filename_with_index_filenames_allowing_periods_in_identifier
expected = {
'/index.html.erb' => '/index.html/',
'/index.html' => '/',
'/index' => '/',
'/foo/index.html.erb' => '/foo/index.html/',
'/foo/index.html' => '/foo/',
'/foo/index' => '/foo/',
}
data_source = new_data_source(allow_periods_in_identifiers: true)
expected.each_pair do |input, expected_output|
actual_output = data_source.send(:identifier_for_filename, input)
assert_equal(
expected_output, actual_output,
"identifier_for_filename(#{input.inspect}) should equal #{expected_output.inspect}, not #{actual_output.inspect}"
)
end
end
def test_identifier_for_filename_with_index_filenames_disallowing_periods_in_identifier
expected = {
'/index.html.erb' => '/',
'/index.html' => '/',
'/index' => '/',
'/foo/index.html.erb' => '/foo/',
'/foo/index.html' => '/foo/',
'/foo/index' => '/foo/',
}
data_source = new_data_source
expected.each_pair do |input, expected_output|
actual_output = data_source.send(:identifier_for_filename, input)
assert_equal(
expected_output, actual_output,
"identifier_for_filename(#{input.inspect}) should equal #{expected_output.inspect}, not #{actual_output.inspect}"
)
end
end
def test_load_objects_allowing_periods_in_identifiers
# Create data source
data_source = new_data_source(allow_periods_in_identifiers: true)
# Create a fake class
klass = Class.new do
attr_reader :stuff
def initialize(*stuff)
@stuff = stuff
end
def ==(other)
@stuff == other.stuff
end
end
# Create sample files
FileUtils.mkdir_p('foo')
FileUtils.mkdir_p('foo/a/b')
File.open('foo/a/b/c.yaml', 'w') { |io| io.write("---\nnum: 1\n") }
File.open('foo/b.c.yaml', 'w') { |io| io.write("---\nnum: 2\n") }
File.open('foo/b.c.html', 'w') { |io| io.write('test 2') }
File.open('foo/car.html', 'w') { |io| io.write('test 3') }
File.open('foo/ugly.yaml~', 'w') { |io| io.write('blah') }
File.open('foo/ugly.html~', 'w') { |io| io.write('blah') }
File.open('foo/ugly.html.orig', 'w') { |io| io.write('blah') }
File.open('foo/ugly.html.rej', 'w') { |io| io.write('blah') }
File.open('foo/ugly.html.bak', 'w') { |io| io.write('blah') }
# Get expected output
expected_out = [
klass.new(
'',
{
'num' => 1,
:content_filename => nil,
:meta_filename => 'foo/a/b/c.yaml',
:extension => nil,
:file => nil,
mtime: File.mtime('foo/a/b/c.yaml'),
},
'/a/b/c/',
),
klass.new(
'test 2',
{
'num' => 2,
:content_filename => 'foo/b.c.html',
:meta_filename => 'foo/b.c.yaml',
:extension => 'html',
:file => File.open('foo/b.c.html'),
mtime: File.mtime('foo/b.c.html') > File.mtime('foo/b.c.yaml') ? File.mtime('foo/b.c.html') : File.mtime('foo/b.c.yaml'),
},
'/b.c/',
),
klass.new(
'test 3',
{
content_filename: 'foo/car.html',
meta_filename: nil,
extension: 'html',
file: File.open('foo/car.html'),
mtime: File.mtime('foo/car.html'),
},
'/car/',
),
]
# Get actual output ordered by identifier
actual_out = data_source.send(:load_objects, 'foo', klass).sort_by { |i| i.stuff[2] }
# Check
(0..expected_out.size - 1).each do |i|
assert_equal expected_out[i].stuff[0], actual_out[i].stuff[0].string, 'content must match'
assert_equal expected_out[i].stuff[2], actual_out[i].stuff[2], 'identifier must match'
['num', :content_filename, :meta_filename, :extension, :mtime].each do |key|
assert_equal expected_out[i].stuff[1][key], actual_out[i].stuff[1][key], "attribute key #{key} must match"
end
end
end
def test_load_objects_disallowing_periods_in_identifiers
# Create data source
data_source = new_data_source
# Create a fake class
klass = Class.new do
attr_reader :stuff
def initialize(*stuff)
@stuff = stuff
end
def ==(other)
@stuff == other.stuff
end
end
# Create sample files
FileUtils.mkdir_p('foo')
FileUtils.mkdir_p('foo/a/b')
File.open('foo/a/b/c.yaml', 'w') { |io| io.write("---\nnum: 1\n") }
File.open('foo/b.yaml', 'w') { |io| io.write("---\nnum: 2\n") }
File.open('foo/b.html.erb', 'w') { |io| io.write('test 2') }
File.open('foo/car.html', 'w') { |io| io.write('test 3') }
File.open('foo/ugly.yaml~', 'w') { |io| io.write('blah') }
File.open('foo/ugly.html~', 'w') { |io| io.write('blah') }
File.open('foo/ugly.html.orig', 'w') { |io| io.write('blah') }
File.open('foo/ugly.html.rej', 'w') { |io| io.write('blah') }
File.open('foo/ugly.html.bak', 'w') { |io| io.write('blah') }
# Get expected output
expected_out = [
klass.new(
'',
{
'num' => 1,
:content_filename => nil,
:meta_filename => 'foo/a/b/c.yaml',
:extension => nil,
:file => nil,
mtime: File.mtime('foo/a/b/c.yaml'),
},
'/a/b/c/',
),
klass.new(
'test 2',
{
'num' => 2,
:content_filename => 'foo/b.html.erb',
:meta_filename => 'foo/b.yaml',
:extension => 'html.erb',
:file => File.open('foo/b.html.erb'),
mtime: File.mtime('foo/b.html.erb') > File.mtime('foo/b.yaml') ? File.mtime('foo/b.html.erb') : File.mtime('foo/b.yaml'),
},
'/b/',
),
klass.new(
'test 3',
{
content_filename: 'foo/car.html',
meta_filename: nil,
extension: 'html',
file: File.open('foo/car.html'),
mtime: File.mtime('foo/car.html'),
},
'/car/',
),
]
# Get actual output ordered by identifier
actual_out = data_source.send(:load_objects, 'foo', klass).sort_by { |i| i.stuff[2] }
# Check
(0..expected_out.size - 1).each do |i|
assert_equal expected_out[i].stuff[0], actual_out[i].stuff[0].string, 'content must match'
assert_equal expected_out[i].stuff[2], actual_out[i].stuff[2], 'identifier must match'
['num', :content_filename, :meta_filename, :extension, :mtime].each do |key|
assert_equal expected_out[i].stuff[1][key], actual_out[i].stuff[1][key], "attribute key #{key} must match"
end
end
end
def test_load_objects_correct_identifier_with_separate_yaml_file
data_source = new_data_source(identifier_type: 'full')
FileUtils.mkdir_p('foo')
File.write('foo/donkey.jpeg', 'data')
File.write('foo/donkey.yaml', "---\nalt: Donkey\n")
objects = data_source.send(:load_objects, 'foo', Nanoc::Int::Item)
assert_equal 1, objects.size
assert_equal '/donkey.jpeg', objects.first.identifier.to_s
end
def test_filename_for
data_source = new_data_source
assert_equal '/foo.bar', data_source.send(:filename_for, '/foo', 'bar')
assert_equal '/foo.bar.baz', data_source.send(:filename_for, '/foo', 'bar.baz')
assert_equal '/foo', data_source.send(:filename_for, '/foo', '')
assert_equal nil, data_source.send(:filename_for, '/foo', nil)
end
def test_compile_iso_8859_1_site
# Create data source
data_source = new_data_source
# Create item
FileUtils.mkdir_p('content')
File.open('content/foo.md', 'w') { |io| io << 'Hëllö' }
# Parse
begin
original_default_external_encoding = Encoding.default_external
Encoding.default_external = 'ISO-8859-1'
items = data_source.items
assert_equal 1, items.size
assert_equal Encoding.find('UTF-8'), items[0].content.string.encoding
ensure
Encoding.default_external = original_default_external_encoding
end
end
def test_compile_iso_8859_1_site_with_explicit_encoding
# Create data source
data_source = new_data_source({})
data_source.config[:encoding] = 'ISO-8859-1'
# Create item
begin
original_default_external_encoding = Encoding.default_external
Encoding.default_external = 'ISO-8859-1'
FileUtils.mkdir_p('content')
File.open('content/foo.md', 'w') { |io| io << 'Hëllö' }
ensure
Encoding.default_external = original_default_external_encoding
end
# Parse
items = data_source.items
assert_equal 1, items.size
assert_equal Encoding.find('UTF-8'), items[0].content.string.encoding
end
def test_all_split_files_in_allowing_periods_in_identifiers
# Create data source
data_source = Nanoc::DataSources::Filesystem.new(nil, nil, nil, allow_periods_in_identifiers: true)
# Write sample files
FileUtils.mkdir_p('foo')
%w[foo.html foo.yaml bar.entry.html foo/qux.yaml].each do |filename|
File.open(filename, 'w') { |io| io.write('test') }
end
# Write stray files
%w[foo.html~ foo.yaml.orig bar.entry.html.bak].each do |filename|
File.open(filename, 'w') { |io| io.write('test') }
end
# Get all files
output_expected = {
'./foo' => ['yaml', ['html']],
'./bar.entry' => [nil, ['html']],
'./foo/qux' => ['yaml', [nil]],
}
output_actual = data_source.send :all_split_files_in, '.'
# Check
assert_equal output_expected, output_actual
end
def test_all_split_files_in_disallowing_periods_in_identifiers
# Create data source
data_source = Nanoc::DataSources::Filesystem.new(nil, nil, nil, nil)
# Write sample files
FileUtils.mkdir_p('foo')
%w[foo.html foo.yaml bar.html.erb foo/qux.yaml].each do |filename|
File.open(filename, 'w') { |io| io.write('test') }
end
# Write stray files
%w[foo.html~ foo.yaml.orig bar.entry.html.bak].each do |filename|
File.open(filename, 'w') { |io| io.write('test') }
end
# Get all files
output_expected = {
'./foo' => ['yaml', ['html']],
'./bar' => [nil, ['html.erb']],
'./foo/qux' => ['yaml', [nil]],
}
output_actual = data_source.send :all_split_files_in, '.'
# Check
assert_equal output_expected, output_actual
end
def test_all_split_files_in_with_multiple_dirs
# Create data source
data_source = Nanoc::DataSources::Filesystem.new(nil, nil, nil, nil)
# Write sample files
%w[aaa/foo.html bbb/foo.html ccc/foo.html].each do |filename|
FileUtils.mkdir_p(File.dirname(filename))
File.open(filename, 'w') { |io| io.write('test') }
end
# Check
expected = {
'./aaa/foo' => [nil, ['html']],
'./bbb/foo' => [nil, ['html']],
'./ccc/foo' => [nil, ['html']],
}
assert_equal expected, data_source.send(:all_split_files_in, '.')
end
def test_all_split_files_in_with_same_extensions
# Create data source
config = { identifier_type: 'full' }
data_source = Nanoc::DataSources::Filesystem.new(nil, nil, nil, config)
# Write sample files
%w[stuff/foo.html stuff/foo.md stuff/foo.yaml].each do |filename|
FileUtils.mkdir_p(File.dirname(filename))
File.open(filename, 'w') { |io| io.write('test') }
end
# Check - { './stuff/foo' => ['yaml', ['html', 'md']] }
res = data_source.send(:all_split_files_in, '.')
assert_equal ['./stuff/foo'], res.keys
assert_equal 2, res.values[0].size
assert_equal 'yaml', res.values[0][0]
assert_equal Array, res.values[0][1].class
assert_equal %w[html md], res.values[0][1].sort
end
def test_all_split_files_in_with_multiple_content_files
# Create data source
data_source = Nanoc::DataSources::Filesystem.new(nil, nil, nil, nil)
# Write sample files
%w[foo.html foo.xhtml foo.txt foo.yaml bar.html qux.yaml].each do |filename|
File.open(filename, 'w') { |io| io.write('test') }
end
# Check
assert_raises(Nanoc::DataSources::Filesystem::Errors::MultipleContentFiles) do
data_source.send(:all_split_files_in, '.')
end
end
def test_basename_of_with_full_style_identifiers
# Create data source
config = { identifier_type: 'full' }
data_source = Nanoc::DataSources::Filesystem.new(nil, nil, nil, config)
# Get input and expected output
expected = {
'/' => '/',
'/foo' => '/foo',
'/foo.html' => '/foo',
'/foo.xyz.html' => '/foo.xyz',
'/foo/bar' => '/foo/bar',
'/foo/bar.html' => '/foo/bar',
'/foo/bar.xyz.html' => '/foo/bar.xyz',
}
# Check
expected.each_pair do |input, expected_output|
actual_output = data_source.send(:basename_of, input)
assert_equal(
expected_output, actual_output,
"basename_of(#{input.inspect}) should equal #{expected_output.inspect}, not #{actual_output.inspect}"
)
end
end
def test_basename_of_allowing_periods_in_identifiers
# Create data source
data_source = Nanoc::DataSources::Filesystem.new(nil, nil, nil, allow_periods_in_identifiers: true)
# Get input and expected output
expected = {
'/' => '/',
'/foo' => '/foo',
'/foo.html' => '/foo',
'/foo.xyz.html' => '/foo.xyz',
'/foo/' => '/foo/',
'/foo.xyz/' => '/foo.xyz/',
'/foo/bar' => '/foo/bar',
'/foo/bar.html' => '/foo/bar',
'/foo/bar.xyz.html' => '/foo/bar.xyz',
'/foo/bar/' => '/foo/bar/',
'/foo/bar.xyz/' => '/foo/bar.xyz/',
'/foo.xyz/bar.xyz/' => '/foo.xyz/bar.xyz/',
}
# Check
expected.each_pair do |input, expected_output|
actual_output = data_source.send(:basename_of, input)
assert_equal(
expected_output, actual_output,
"basename_of(#{input.inspect}) should equal #{expected_output.inspect}, not #{actual_output.inspect}"
)
end
end
def test_basename_of_disallowing_periods_in_identifiers
# Create data source
data_source = Nanoc::DataSources::Filesystem.new(nil, nil, nil, nil)
# Get input and expected output
expected = {
'/' => '/',
'/foo' => '/foo',
'/foo.html' => '/foo',
'/foo.xyz.html' => '/foo',
'/foo/' => '/foo/',
'/foo.xyz/' => '/foo.xyz/',
'/foo/bar' => '/foo/bar',
'/foo/bar.html' => '/foo/bar',
'/foo/bar.xyz.html' => '/foo/bar',
'/foo/bar/' => '/foo/bar/',
'/foo/bar.xyz/' => '/foo/bar.xyz/',
'/foo.xyz/bar.xyz/' => '/foo.xyz/bar.xyz/',
}
# Check
expected.each_pair do |input, expected_output|
actual_output = data_source.send(:basename_of, input)
assert_equal(
expected_output, actual_output,
"basename_of(#{input.inspect}) should equal #{expected_output.inspect}, not #{actual_output.inspect}"
)
end
end
def test_ext_of_allowing_periods_in_identifiers
# Create data source
data_source = Nanoc::DataSources::Filesystem.new(nil, nil, nil, allow_periods_in_identifiers: true)
# Get input and expected output
expected = {
'/' => '',
'/foo' => '',
'/foo.html' => '.html',
'/foo.xyz.html' => '.html',
'/foo/' => '',
'/foo.xyz/' => '',
'/foo/bar' => '',
'/foo/bar.html' => '.html',
'/foo/bar.xyz.html' => '.html',
'/foo/bar/' => '',
'/foo/bar.xyz/' => '',
'/foo.xyz/bar.xyz/' => '',
}
# Check
expected.each_pair do |input, expected_output|
actual_output = data_source.send(:ext_of, input)
assert_equal(
expected_output, actual_output,
"basename_of(#{input.inspect}) should equal #{expected_output.inspect}, not #{actual_output.inspect}"
)
end
end
def test_ext_of_disallowing_periods_in_identifiers
# Create data source
data_source = Nanoc::DataSources::Filesystem.new(nil, nil, nil, nil)
# Get input and expected output
expected = {
'/' => '',
'/foo' => '',
'/foo.html' => '.html',
'/foo.xyz.html' => '.xyz.html',
'/foo/' => '',
'/foo.xyz/' => '',
'/foo/bar' => '',
'/foo/bar.html' => '.html',
'/foo/bar.xyz.html' => '.xyz.html',
'/foo/bar/' => '',
'/foo/bar.xyz/' => '',
'/foo.xyz/bar.xyz/' => '',
}
# Check
expected.each_pair do |input, expected_output|
actual_output = data_source.send(:ext_of, input)
assert_equal(
expected_output, actual_output,
"basename_of(#{input.inspect}) should equal #{expected_output.inspect}, not #{actual_output.inspect}"
)
end
end
end
nanoc-4.11.0/nanoc/test/data_sources/test_filesystem_tools.rb000066400000000000000000000113251340050175000244110ustar00rootroot00000000000000# frozen_string_literal: true
require 'helper'
class Nanoc::DataSources::FilesystemToolsTest < Nanoc::TestCase
def setup
super
skip_unless_symlinks_supported
end
def test_all_files_in_follows_symlinks_to_dirs
# Write sample files
(0..15).each do |i|
FileUtils.mkdir_p("dir#{i}")
File.open("dir#{i}/foo.md", 'w') { |io| io.write('o hai') }
end
(1..10).each do |i|
File.symlink("../dir#{i}", "dir#{i - 1}/sub")
end
# Check
# 11 expected files (follow symlink 10 times)
# sort required because 10 comes before 2
expected_files = [
'dir0/foo.md',
'dir0/sub/foo.md',
'dir0/sub/sub/foo.md',
'dir0/sub/sub/sub/foo.md',
'dir0/sub/sub/sub/sub/foo.md',
'dir0/sub/sub/sub/sub/sub/foo.md',
'dir0/sub/sub/sub/sub/sub/sub/foo.md',
'dir0/sub/sub/sub/sub/sub/sub/sub/foo.md',
'dir0/sub/sub/sub/sub/sub/sub/sub/sub/foo.md',
'dir0/sub/sub/sub/sub/sub/sub/sub/sub/sub/foo.md',
'dir0/sub/sub/sub/sub/sub/sub/sub/sub/sub/sub/foo.md',
]
actual_files = Nanoc::DataSources::Filesystem::Tools.all_files_in('dir0', nil).sort
assert_equal expected_files, actual_files
end
def test_all_files_in_follows_symlinks_to_dirs_too_many
# Write sample files
(0..15).each do |i|
FileUtils.mkdir_p("dir#{i}")
File.open("dir#{i}/foo.md", 'w') { |io| io.write('o hai') }
end
(1..15).each do |i|
File.symlink("../dir#{i}", "dir#{i - 1}/sub")
end
assert_raises Nanoc::DataSources::Filesystem::Tools::MaxSymlinkDepthExceededError do
Nanoc::DataSources::Filesystem::Tools.all_files_in('dir0', nil)
end
end
def test_all_files_in_relativizes_directory_names
FileUtils.mkdir('foo')
FileUtils.mkdir('bar')
File.open('foo/x.md', 'w') { |io| io.write('o hai from foo/x') }
File.open('bar/y.md', 'w') { |io| io.write('o hai from bar/y') }
File.symlink('../bar', 'foo/barlink')
expected_files = ['foo/barlink/y.md', 'foo/x.md']
actual_files = Nanoc::DataSources::Filesystem::Tools.all_files_in('foo', nil).sort
assert_equal expected_files, actual_files
end
def test_all_files_in_follows_symlinks_to_files
# Write sample files
File.open('bar', 'w') { |io| io.write('o hai from bar') }
FileUtils.mkdir_p('dir')
File.open('dir/foo', 'w') { |io| io.write('o hai from foo') }
File.symlink('../bar', 'dir/bar-link')
# Check
expected_files = ['dir/bar-link', 'dir/foo']
actual_files = Nanoc::DataSources::Filesystem::Tools.all_files_in('dir', nil).sort
assert_equal expected_files, actual_files
end
def test_resolve_symlink
File.open('foo', 'w') { |io| io.write('o hai') }
File.symlink('foo', 'bar')
File.symlink('bar', 'baz')
File.symlink('baz', 'qux')
expected = File.expand_path('foo')
actual = Nanoc::DataSources::Filesystem::Tools.resolve_symlink('qux')
assert_equal expected, actual
end
def test_resolve_symlink_too_many
File.open('foo', 'w') { |io| io.write('o hai') }
File.symlink('foo', 'symlin-0')
(1..7).each do |i|
File.symlink("symlink-#{i - 1}", "symlink-#{i}")
end
assert_raises Nanoc::DataSources::Filesystem::Tools::MaxSymlinkDepthExceededError do
Nanoc::DataSources::Filesystem::Tools.resolve_symlink('symlink-7')
end
end
def test_unwanted_dotfiles_not_found
# Write sample files
FileUtils.mkdir_p('dir')
File.open('dir/.DS_Store', 'w') { |io| io.write('o hai') }
File.open('dir/.htaccess', 'w') { |io| io.write('o hai') }
actual_files = Nanoc::DataSources::Filesystem::Tools.all_files_in('dir', nil).sort
assert_equal [], actual_files
end
def test_user_dotfiles_are_valid_items
# Write sample files
FileUtils.mkdir_p('dir')
File.open('dir/.other', 'w') { |io| io.write('o hai') }
actual_files = Nanoc::DataSources::Filesystem::Tools.all_files_in('dir', '**/.other').sort
assert_equal ['dir/.other'], actual_files
end
def test_multiple_user_dotfiles_are_valid_items
# Write sample files
FileUtils.mkdir_p('dir')
File.open('dir/.other', 'w') { |io| io.write('o hai') }
File.open('dir/.DS_Store', 'w') { |io| io.write('o hai') }
actual_files = Nanoc::DataSources::Filesystem::Tools.all_files_in('dir', ['**/.other', '**/.DS_Store']).sort
assert_equal ['dir/.other', 'dir/.DS_Store'].sort, actual_files.sort
end
def test_unknown_pattern
# Write sample files
FileUtils.mkdir_p('dir')
File.open('dir/.other', 'w') { |io| io.write('o hai') }
pattern = { dotfiles: '**/.other' }
assert_raises Nanoc::Int::Errors::GenericTrivial, "Do not know how to handle extra_files: #{pattern.inspect}" do
Nanoc::DataSources::Filesystem::Tools.all_files_in('dir0', pattern)
end
end
end
nanoc-4.11.0/nanoc/test/deploying/000077500000000000000000000000001340050175000167355ustar00rootroot00000000000000nanoc-4.11.0/nanoc/test/deploying/test_fog.rb000066400000000000000000000043751340050175000211050ustar00rootroot00000000000000# frozen_string_literal: true
require 'helper'
class Nanoc::Deploying::Deployers::FogTest < Nanoc::TestCase
def test_read_etags_with_local_provider
fog = Nanoc::Deploying::Deployers::Fog.new(
'output/', provider: 'local'
)
files = [
mock('file_a'),
mock('file_b'),
]
assert_equal({}, fog.send(:read_etags, files))
end
def test_read_etags_with_aws_provider
fog = Nanoc::Deploying::Deployers::Fog.new(
'output/', provider: 'aws'
)
files = [
mock('file_a', key: 'key_a', etag: 'etag_a'),
mock('file_b', key: 'key_b', etag: 'etag_b'),
]
expected = {
'key_a' => 'etag_a',
'key_b' => 'etag_b',
}
assert_equal(expected, fog.send(:read_etags, files))
end
def test_calc_local_etag_with_local_provider
fog = Nanoc::Deploying::Deployers::Fog.new(
'output/', provider: 'local'
)
file_path = 'blah.tmp'
File.write(file_path, 'hallo')
assert_nil fog.send(:calc_local_etag, file_path)
end
def test_calc_local_etag_with_aws_provider
fog = Nanoc::Deploying::Deployers::Fog.new(
'output/', provider: 'aws'
)
file_path = 'blah.tmp'
File.write(file_path, 'hallo')
assert_equal(
'598d4c200461b81522a3328565c25f7c',
fog.send(:calc_local_etag, file_path),
)
end
def test_needs_upload_with_missing_remote_etag
fog = Nanoc::Deploying::Deployers::Fog.new(
'output/', provider: 'aws'
)
file_path = 'blah.tmp'
File.write(file_path, 'hallo')
key = 'some_key'
etags = {}
assert fog.send(:needs_upload?, key, file_path, etags)
end
def test_needs_upload_with_different_etags
fog = Nanoc::Deploying::Deployers::Fog.new(
'output/', provider: 'aws'
)
file_path = 'blah.tmp'
File.write(file_path, 'hallo')
key = 'some_key'
etags = { key => 'some_etag' }
assert fog.send(:needs_upload?, key, file_path, etags)
end
def test_needs_upload_with_identical_etags
fog = Nanoc::Deploying::Deployers::Fog.new(
'output/', provider: 'aws'
)
file_path = 'blah.tmp'
File.write(file_path, 'hallo')
key = 'some_key'
etags = { key => '598d4c200461b81522a3328565c25f7c' }
refute fog.send(:needs_upload?, key, file_path, etags)
end
end
nanoc-4.11.0/nanoc/test/deploying/test_git.rb000066400000000000000000000144331340050175000211110ustar00rootroot00000000000000# frozen_string_literal: true
class Nanoc::Deploying::Deployers::GitTest < Nanoc::TestCase
def test_run_with_defaults_options
# Create deployer
git = Nanoc::Deploying::Deployers::Git.new(
'output/',
{}
)
# Mock run_cmd
def git.run_cmd(args, _opts = {})
@shell_cmd_args = [] unless defined? @shell_cmd_args
@shell_cmd_args << args.join(' ')
end
# Mock clean_repo?
def git.clean_repo?
false
end
# Create output dir + repo
FileUtils.mkdir_p('output')
Dir.chdir('output') { system('git', 'init', '--quiet') }
# Try running
git.run
commands = <<~EOS
git config --get remote.origin.url
git checkout master
git add -A
git commit -a --author Nanoc <> -m Automated commit at .+ by Nanoc \\d+\\.\\d+\\.\\d+\\w*
git push origin master
EOS
assert_match Regexp.new(/^#{commands.chomp}$/), (git.instance_eval { @shell_cmd_args.join("\n") })
end
def test_run_with_clean_repository
# Create deployer
git = Nanoc::Deploying::Deployers::Git.new(
'output/',
{}
)
# Mock run_cmd
def git.run_cmd(args, _opts = {})
@shell_cmd_args = [] unless defined? @shell_cmd_args
@shell_cmd_args << args.join(' ')
end
# Mock clean_repo?
def git.clean_repo?
true
end
# Create output dir + repo
FileUtils.mkdir_p('output')
Dir.chdir('output') { system('git', 'init', '--quiet') }
# Try running
git.run
commands = <<~EOS
git config --get remote.origin.url
git checkout master
EOS
assert_match Regexp.new(/^#{commands.chomp}$/), (git.instance_eval { @shell_cmd_args.join("\n") })
end
def test_run_with_custom_options
# Create deployer
git = Nanoc::Deploying::Deployers::Git.new(
'output/',
remote: 'github', branch: 'gh-pages', forced: true,
)
# Mock run_cmd
def git.run_cmd(args, _opts = {})
@shell_cmd_args = [] unless defined? @shell_cmd_args
@shell_cmd_args << args.join(' ')
end
# Mock clean_repo?
def git.clean_repo?
false
end
# Create output dir + repo
FileUtils.mkdir_p('output')
Dir.chdir('output') { system('git', 'init', '--quiet') }
# Try running
git.run
commands = <<~EOS
git config --get remote.github.url
git checkout gh-pages
git add -A
git commit -a --author Nanoc <> -m Automated commit at .+ by Nanoc \\d+\\.\\d+\\.\\d+\\w*
git push -f github gh-pages
EOS
assert_match Regexp.new(/^#{commands.chomp}$/), (git.instance_eval { @shell_cmd_args.join("\n") })
end
def test_run_without_git_init
# Create deployer
git = Nanoc::Deploying::Deployers::Git.new(
'output/',
{}
)
# Mock run_cmd
def git.run_cmd(args, _opts = {})
@shell_cmd_args = [] unless defined? @shell_cmd_args
@shell_cmd_args << args.join(' ')
end
# Mock clean_repo?
def git.clean_repo?
false
end
# Create site
FileUtils.mkdir_p('output/.git')
# Try running
git.run
commands = <<~EOS
git config --get remote.origin.url
git checkout master
git add -A
git commit -a --author Nanoc <> -m Automated commit at .+ by Nanoc \\d+\\.\\d+\\.\\d+\\w*
git push origin master
EOS
assert_match Regexp.new(/^#{commands.chomp}$/), (git.instance_eval { @shell_cmd_args.join("\n") })
end
def test_run_with_ssh_url
# Create deployer
git = Nanoc::Deploying::Deployers::Git.new(
'output/',
remote: 'git@github.com:myself/myproject.git',
)
# Mock run_cmd
def git.run_cmd(args, _opts = {})
@shell_cmd_args = [] unless defined? @shell_cmd_args
@shell_cmd_args << args.join(' ')
end
# Mock clean_repo?
def git.clean_repo?
false
end
# Create output dir + repo
FileUtils.mkdir_p('output')
Dir.chdir('output') { system('git', 'init', '--quiet') }
# Try running
git.run
commands = <<~EOS
git checkout master
git add -A
git commit -a --author Nanoc <> -m Automated commit at .+ by Nanoc \\d+\\.\\d+\\.\\d+\\w*
git push git@github.com:myself/myproject.git master
EOS
assert_match Regexp.new(/^#{commands.chomp}$/), (git.instance_eval { @shell_cmd_args.join("\n") })
end
def test_run_with_http_url
# Create deployer
git = Nanoc::Deploying::Deployers::Git.new(
'output/',
remote: 'https://github.com/nanoc/nanoc.git',
)
# Mock run_cmd
def git.run_cmd(args, _opts = {})
@shell_cmd_args = [] unless defined? @shell_cmd_args
@shell_cmd_args << args.join(' ')
end
# Mock clean_repo?
def git.clean_repo?
false
end
# Create output dir + repo
FileUtils.mkdir_p('output')
Dir.chdir('output') { system('git', 'init', '--quiet') }
# Try running
git.run
commands = <<~EOS
git checkout master
git add -A
git commit -a --author Nanoc <> -m Automated commit at .+ by Nanoc \\d+\\.\\d+\\.\\d+\\w*
git push https://github.com/nanoc/nanoc.git master
EOS
assert_match Regexp.new(/^#{commands.chomp}$/), (git.instance_eval { @shell_cmd_args.join("\n") })
end
def test_clean_repo_on_a_clean_repo
# Create deployer
git = Nanoc::Deploying::Deployers::Git.new(
'output/',
remote: 'https://github.com/nanoc/nanoc.git',
)
FileUtils.mkdir_p('output')
piper = Nanoc::Extra::Piper.new(stdout: $stdout, stderr: $stderr)
Dir.chdir('output') do
piper.run('git init', nil)
assert git.send(:clean_repo?)
end
end
def test_clean_repo_on_a_dirty_repo
# Create deployer
git = Nanoc::Deploying::Deployers::Git.new(
'output/',
remote: 'https://github.com/nanoc/nanoc.git',
)
FileUtils.mkdir_p('output')
piper = Nanoc::Extra::Piper.new(stdout: $stdout, stderr: $stderr)
Dir.chdir('output') do
piper.run('git init', nil)
FileUtils.touch('foobar')
refute git.send(:clean_repo?)
end
end
def test_clean_repo_not_git_repo
# Create deployer
git = Nanoc::Deploying::Deployers::Git.new(
'output/',
remote: 'https://github.com/nanoc/nanoc.git',
)
FileUtils.mkdir_p('output')
Dir.chdir('output') do
assert_raises Nanoc::Extra::Piper::Error do
git.send(:clean_repo?)
end
end
end
end
nanoc-4.11.0/nanoc/test/deploying/test_rsync.rb000066400000000000000000000037571340050175000214730ustar00rootroot00000000000000# frozen_string_literal: true
require 'helper'
class Nanoc::Deploying::Deployers::RsyncTest < Nanoc::TestCase
def setup
super
skip_unless_have_command 'rsync'
end
def test_run_without_dst
# Create deployer
rsync = Nanoc::Deploying::Deployers::Rsync.new(
'output/',
{},
)
# Mock run_shell_cmd
def rsync.run_shell_cmd(args)
@shell_cms_args = args
end
# Try running
error = assert_raises(RuntimeError) do
rsync.run
end
# Check error message
assert_equal 'No dst found in deployment configuration', error.message
end
def test_run_with_erroneous_dst
# Create deployer
rsync = Nanoc::Deploying::Deployers::Rsync.new(
'output/',
dst: 'asdf/',
)
# Mock run_shell_cmd
def rsync.run_shell_cmd(args)
@shell_cms_args = args
end
# Try running
error = assert_raises(RuntimeError) do
rsync.run
end
# Check error message
assert_equal 'dst requires no trailing slash', error.message
end
def test_run_everything_okay
# Create deployer
rsync = Nanoc::Deploying::Deployers::Rsync.new(
'output',
dst: 'asdf',
)
# Mock run_shell_cmd
def rsync.run_shell_cmd(args)
@shell_cms_args = args
end
# Run
rsync.run
# Check args
opts = Nanoc::Deploying::Deployers::Rsync::DEFAULT_OPTIONS
assert_equal(
['rsync', opts, 'output/', 'asdf'].flatten,
rsync.instance_eval { @shell_cms_args },
)
end
def test_run_everything_okay_dry
# Create deployer
rsync = Nanoc::Deploying::Deployers::Rsync.new(
'output',
{ dst: 'asdf' },
dry_run: true,
)
# Mock run_shell_cmd
def rsync.run_shell_cmd(args)
@shell_cms_args = args
end
# Run
rsync.run
# Check args
opts = Nanoc::Deploying::Deployers::Rsync::DEFAULT_OPTIONS
assert_equal(
['echo', 'rsync', opts, 'output/', 'asdf'].flatten,
rsync.instance_eval { @shell_cms_args },
)
end
end
nanoc-4.11.0/nanoc/test/extra/000077500000000000000000000000001340050175000160665ustar00rootroot00000000000000nanoc-4.11.0/nanoc/test/extra/core_ext/000077500000000000000000000000001340050175000176765ustar00rootroot00000000000000nanoc-4.11.0/nanoc/test/extra/core_ext/test_time.rb000066400000000000000000000010251340050175000222160ustar00rootroot00000000000000# frozen_string_literal: true
require 'helper'
class Nanoc::ExtraCoreExtTimeTest < Nanoc::TestCase
def test___nanoc_to_iso8601_date_utc
assert_equal('2008-05-19', Time.utc(2008, 5, 19, 14, 20, 0, 0).__nanoc_to_iso8601_date)
end
def test___nanoc_to_iso8601_date_non_utc
assert_equal('2008-05-18', Time.new(2008, 5, 19, 0, 0, 0, '+02:00').__nanoc_to_iso8601_date)
end
def test___nanoc_to_iso8601_time
assert_equal('2008-05-19T14:20:00Z', Time.utc(2008, 5, 19, 14, 20, 0, 0).__nanoc_to_iso8601_time)
end
end
nanoc-4.11.0/nanoc/test/extra/test_link_collector.rb000066400000000000000000000061021340050175000224540ustar00rootroot00000000000000# frozen_string_literal: true
require 'helper'
class Nanoc::Extra::LinkCollectorTest < Nanoc::TestCase
def test_all
# Create dummy data
File.open('file-a.html', 'w') do |io|
io << %(A 1
)
io << %(A 2
)
io << %(
)
io << %(A 4)
io << %(A 5
)
end
File.open('file-b.html', 'w') do |io|
io << %(B 1
)
io << %(B 2
)
io << %(B 3
)
end
# Create validator
collector = Nanoc::Extra::LinkCollector.new(%w[file-a.html file-b.html])
# Test
hrefs_with_filenames = collector.filenames_per_href
hrefs = hrefs_with_filenames.keys
assert_includes hrefs, 'http://example.com/'
assert_includes hrefs, 'https://example.com/'
assert_includes hrefs, 'stuff/'
refute_includes hrefs, nil
assert_includes hrefs, 'mailto:bob@example.com'
assert_includes hrefs, '../stuff'
assert_includes hrefs, '/stuff'
refute_includes hrefs, 'https://example.com/with-fragment#moo'
assert_includes hrefs, 'https://example.com/with-fragment'
end
def test_external
# Create dummy data
File.open('file-a.html', 'w') do |io|
io << %(A 1
)
io << %(A 2
)
io << %(
)
end
File.open('file-b.html', 'w') do |io|
io << %(B 1
)
io << %(B 2
)
io << %(B 3
)
end
# Create validator
collector = Nanoc::Extra::LinkCollector.new(%w[file-a.html file-b.html], :external)
# Test
hrefs_with_filenames = collector.filenames_per_href
hrefs = hrefs_with_filenames.keys
assert_includes hrefs, 'http://example.com/'
assert_includes hrefs, 'https://example.com/'
refute_includes hrefs, 'stuff/'
assert_includes hrefs, 'mailto:bob@example.com'
refute_includes hrefs, '../stuff'
refute_includes hrefs, '/stuff'
end
def test_internal
# Create dummy data
File.open('file-a.html', 'w') do |io|
io << %(A 1
)
io << %(A 2
)
io << %(
)
end
File.open('file-b.html', 'w') do |io|
io << %(B 1
)
io << %(B 2
)
io << %(B 3
)
end
# Create validator
collector = Nanoc::Extra::LinkCollector.new(%w[file-a.html file-b.html], :internal)
# Test
hrefs_with_filenames = collector.filenames_per_href
hrefs = hrefs_with_filenames.keys
refute_includes hrefs, 'http://example.com/'
refute_includes hrefs, 'https://example.com/'
assert_includes hrefs, 'stuff/'
refute_includes hrefs, 'mailto:bob@example.com'
assert_includes hrefs, '../stuff'
assert_includes hrefs, '/stuff'
end
end
nanoc-4.11.0/nanoc/test/extra/test_piper.rb000066400000000000000000000021361340050175000205730ustar00rootroot00000000000000# frozen_string_literal: true
require 'helper'
class Nanoc::Extra::PiperTest < Nanoc::TestCase
def test_basic
stdout = StringIO.new
stderr = StringIO.new
cmd = %w[ls -l]
File.open('foo.txt', 'w') { |io| io.write('hi') }
File.open('bar.txt', 'w') { |io| io.write('ho') }
piper = Nanoc::Extra::Piper.new(stdout: stdout, stderr: stderr)
piper.run(cmd, nil)
assert_match(/foo\.txt/, stdout.string)
assert_match(/bar\.txt/, stdout.string)
assert stderr.string.empty?
end
def test_stdin
stdout = StringIO.new
stderr = StringIO.new
input = 'Hello World!'
cmd = %w[cat]
piper = Nanoc::Extra::Piper.new(stdout: stdout, stderr: stderr)
piper.run(cmd, input)
assert_equal(input, stdout.string)
assert_equal('', stderr.string)
end
def test_no_such_command
stdout = StringIO.new
stderr = StringIO.new
cmd = %w[cat kafhawilgoiwaejagoualjdsfilofiewaguihaifeowuiga]
piper = Nanoc::Extra::Piper.new(stdout: stdout, stderr: stderr)
assert_raises(Nanoc::Extra::Piper::Error) do
piper.run(cmd, nil)
end
end
end
nanoc-4.11.0/nanoc/test/filters/000077500000000000000000000000001340050175000164135ustar00rootroot00000000000000nanoc-4.11.0/nanoc/test/filters/colorize_syntax/000077500000000000000000000000001340050175000216475ustar00rootroot00000000000000nanoc-4.11.0/nanoc/test/filters/colorize_syntax/test_coderay.rb000066400000000000000000000164021340050175000246640ustar00rootroot00000000000000# frozen_string_literal: true
require 'helper'
class Nanoc::Filters::ColorizeSyntax::CoderayTest < Nanoc::TestCase
CODERAY_PRE = ''
CODERAY_POST = ''
def test_coderay_simple
if_have 'nokogiri' do
# Create filter
filter = ::Nanoc::Filters::ColorizeSyntax.new
# Get input and expected output
input = '# comment
'
expected_output = CODERAY_PRE + '# comment
' + CODERAY_POST
# Run filter
actual_output = filter.setup_and_run(input)
assert_equal(expected_output, actual_output)
end
end
def test_coderay_with_comment
if_have 'nokogiri' do
# Create filter
filter = ::Nanoc::Filters::ColorizeSyntax.new
# Get input and expected output
input = %(#!ruby
# comment
)
expected_output = CODERAY_PRE + '# comment
' + CODERAY_POST
# Run filter
actual_output = filter.setup_and_run(input)
assert_equal(expected_output, actual_output)
end
end
def test_coderay_with_comment_in_middle
if_have 'nokogiri' do
# Create filter
filter = ::Nanoc::Filters::ColorizeSyntax.new
# Get input and expected output
input = %(def moo ; end
#!ruby
# comment
)
expected_output = "def moo ; end\n#!ruby\n# comment
"
# Run filter
actual_output = filter.setup_and_run(input)
assert_equal(expected_output, actual_output)
end
end
def test_coderay_with_comment_and_class
if_have 'nokogiri' do
# Create filter
filter = ::Nanoc::Filters::ColorizeSyntax.new
# Get input and expected output
input = %(#!ruby
# comment
)
expected_output = CODERAY_PRE + %(#!ruby
# comment
) + CODERAY_POST
# Run filter
actual_output = filter.setup_and_run(input)
assert_equal(expected_output, actual_output)
end
end
def test_coderay_with_more_classes
if_have 'nokogiri' do
# Create filter
filter = ::Nanoc::Filters::ColorizeSyntax.new
# Get input and expected output
input = '# comment
'
expected_output = CODERAY_PRE + '# comment
' + CODERAY_POST
# Run filter
actual_output = filter.setup_and_run(input)
assert_equal(expected_output, actual_output)
end
end
def test_colorize_syntax_with_unknown_syntax
if_have 'nokogiri' do
# Create filter
filter = ::Nanoc::Filters::ColorizeSyntax.new
# Run filter
assert_raises RuntimeError do
filter.setup_and_run('whatever
', syntax: :kasflwafhaweoineurl)
end
end
end
def test_colorize_syntax_with_xml
if_have 'nokogiri' do
# Create filter
filter = ::Nanoc::Filters::ColorizeSyntax.new
# Get input and expected output
input = 'foo
bar
'
expected_output = 'foo
bar
'
# Run filter
actual_output = filter.setup_and_run(input, syntax: :xml)
assert_equal(expected_output, actual_output)
end
end
def test_colorize_syntax_with_xhtml
if_have 'nokogiri' do
# Create filter
filter = ::Nanoc::Filters::ColorizeSyntax.new
# Get input and expected output
input = 'foo
bar
'
expected_output = 'foo
bar
'
# Run filter
actual_output = filter.setup_and_run(input, syntax: :xhtml)
assert_equal(expected_output, actual_output)
end
end
def test_colorize_syntax_with_non_language_shebang_line
if_have 'nokogiri' do
# Create filter
filter = ::Nanoc::Filters::ColorizeSyntax.new
# Get input and expected output
input = <<~EOS
before
#!/usr/bin/env ruby
puts 'hi!'
after
EOS
expected_output = <<~EOS.sub(/\s*\Z/m, '')
before
#!/usr/bin/env ruby
puts 'hi!'
after
EOS
# Run filter
actual_output = filter.setup_and_run(input).sub(/\s*\Z/m, '')
assert_equal(expected_output, actual_output)
end
end
def test_colorize_syntax_with_non_language_shebang_line_and_language_line
if_have 'nokogiri' do
# Create filter
filter = ::Nanoc::Filters::ColorizeSyntax.new
# Get input and expected output
input = <<~EOS
before
#!ruby
#!/usr/bin/env ruby
puts 'hi!'
after
EOS
expected_output = <<~EOS.sub(/\s*\Z/m, '')
before
#{CODERAY_PRE}#!/usr/bin/env ruby
puts 'hi!'
#{CODERAY_POST}
after
EOS
# Run filter
actual_output = filter.setup_and_run(input).sub(/\s*\Z/m, '')
assert_equal(expected_output, actual_output)
end
end
def test_not_outside_pre
if_have 'nokogiri' do
# Create filter
filter = ::Nanoc::Filters::ColorizeSyntax.new
# Get input and expected output
input = '# comment
'
expected_output = '# comment
'
# Run filter
actual_output = filter.setup_and_run(input, outside_pre: false)
assert_equal(expected_output, actual_output)
end
end
def test_outside_pre
if_have 'nokogiri' do
# Create filter
filter = ::Nanoc::Filters::ColorizeSyntax.new
# Get input and expected output
input = '# comment
'
expected_output = '# comment
'
# Run filter
actual_output = filter.setup_and_run(input, outside_pre: true)
assert_equal(expected_output, actual_output)
end
end
def test_strip
if_have 'nokogiri' do
# Create filter
filter = ::Nanoc::Filters::ColorizeSyntax.new
# Simple test
assert_equal ' bar', filter.send(:strip, "\n bar")
# Get input and expected output
input = <<~EOS
before
def foo
end
after
EOS
expected_output = <<~EOS.sub(/\s*\Z/m, '')
before
#{CODERAY_PRE} def foo
end
#{CODERAY_POST}
after
EOS
# Run filter
actual_output = filter.setup_and_run(input).sub(/\s*\Z/m, '')
assert_equal(expected_output, actual_output)
end
end
end
nanoc-4.11.0/nanoc/test/filters/colorize_syntax/test_common.rb000066400000000000000000000065761340050175000245410ustar00rootroot00000000000000# frozen_string_literal: true
require 'helper'
class Nanoc::Filters::ColorizeSyntax::CommonTest < Nanoc::TestCase
def test_dummy
if_have 'nokogiri' do
# Create filter
filter = ::Nanoc::Filters::ColorizeSyntax.new
# Get input and expected output
input = '# comment
'
expected_output = input # because we are using a dummy
# Run filter
actual_output = filter.setup_and_run(input, default_colorizer: :dummy)
assert_equal(expected_output, actual_output)
end
end
def test_with_frozen_input
if_have 'nokogiri' do
input = '# comment
'
input.freeze
filter = ::Nanoc::Filters::ColorizeSyntax.new
filter.setup_and_run(input, default_colorizer: :dummy)
end
end
def test_full_page
if_have 'nokogiri' do
# Create filter
filter = ::Nanoc::Filters::ColorizeSyntax.new
# Get input and expected output
input = <<~EOS
Foo
# comment
EOS
expected_output_regex = %r{^\s*\s*\s*\s*Foo \s*\s*\s*# comment
\s*\s*}
# Run filter
actual_output = filter.setup_and_run(input, default_colorizer: :dummy, is_fullpage: true)
assert_match expected_output_regex, actual_output
end
end
def test_full_page_html5
skip_unless_have 'nokogumbo'
# Create filter
filter = ::Nanoc::Filters::ColorizeSyntax.new
# Get input and expected output
input = <<~EOS
Foo
# comment
EOS
expected_output_regex = %r{^\s*\s*\s*\s*Foo \s*\s*\s*# comment
\s*\s*}
# Run filter
actual_output = filter.setup_and_run(input, syntax: :html5, default_colorizer: :dummy, is_fullpage: true)
assert_match expected_output_regex, actual_output
end
def test_colorize_syntax_with_missing_executables
if_have 'nokogiri' do
begin
original_path = ENV['PATH']
ENV['PATH'] = './blooblooblah'
# Create filter
filter = ::Nanoc::Filters::ColorizeSyntax.new
# Get input and expected output
input = 'puts "foo"
'
# Run filter
%i[albino pygmentize simon_highlight].each do |colorizer|
begin
input = 'puts "foo"
'
filter.setup_and_run(
input,
colorizers: { ruby: colorizer },
)
flunk 'expected colorizer to raise if no executable is available'
rescue
end
end
ensure
ENV['PATH'] = original_path
end
end
end
end
nanoc-4.11.0/nanoc/test/filters/colorize_syntax/test_pygmentize.rb000066400000000000000000000024321340050175000254270ustar00rootroot00000000000000# frozen_string_literal: true
require 'helper'
class Nanoc::Filters::ColorizeSyntax::PygmentizeTest < Nanoc::TestCase
def test_pygmentize
if_have 'nokogiri' do
skip_unless_have_command 'pygmentize'
# Create filter
filter = ::Nanoc::Filters::ColorizeSyntax.new
# Get input and expected output
input = '# comment
'
expected_output = '# comment
'
# Run filter
actual_output = filter.setup_and_run(input, colorizers: { ruby: :pygmentize })
assert_equal(expected_output, actual_output)
end
end
def test_colorize_syntax_with_default_colorizer
skip_unless_have_command 'pygmentize'
if_have 'nokogiri' do
# Create filter
filter = ::Nanoc::Filters::ColorizeSyntax.new
# Get input and expected output
input = 'puts "foo"
'
expected_output = 'puts "foo"
'
# Run filter
actual_output = filter.setup_and_run(input, default_colorizer: :pygmentize)
assert_equal(expected_output, actual_output)
end
end
end
nanoc-4.11.0/nanoc/test/filters/colorize_syntax/test_pygments.rb000066400000000000000000000013401340050175000250770ustar00rootroot00000000000000# frozen_string_literal: true
require 'helper'
class Nanoc::Filters::ColorizeSyntax::PygmentsTest < Nanoc::TestCase
def test_pygmentsrb
skip 'pygments.rb does not support Windows' if on_windows?
if_have 'pygments', 'nokogiri' do
# Create filter
filter = ::Nanoc::Filters::ColorizeSyntax.new
# Get input and expected output
input = '# comment…
'
expected_output = '# comment…
'
# Run filter
actual_output = filter.setup_and_run(input, colorizers: { ruby: :pygmentsrb })
assert_equal(expected_output, actual_output)
end
end
end
nanoc-4.11.0/nanoc/test/filters/colorize_syntax/test_simon.rb000066400000000000000000000013061340050175000243600ustar00rootroot00000000000000# frozen_string_literal: true
require 'helper'
class Nanoc::Filters::ColorizeSyntax::SimonTest < Nanoc::TestCase
def test_simon_highlight
if_have 'nokogiri' do
skip_unless_have_command 'highlight'
# Create filter
filter = ::Nanoc::Filters::ColorizeSyntax.new
# Get input and expected output
input = %(
# comment
)
expected_output = '# comment
'
# Run filter
actual_output = filter.setup_and_run(input, default_colorizer: :simon_highlight)
assert_equal(expected_output, actual_output)
end
end
end
nanoc-4.11.0/nanoc/test/filters/test_bluecloth.rb000066400000000000000000000011061340050175000217560ustar00rootroot00000000000000# frozen_string_literal: true
require 'helper'
class Nanoc::Filters::BlueClothTest < Nanoc::TestCase
def test_filter
skip_unless_have 'bluecloth'
# Skip if nonfunctional
begin
::BlueCloth.new('# hi').to_html
rescue ArgumentError => e
skip 'BlueCloth is broken on this platform' if e.message.include?('wrong number of arguments')
end
# Create filter
filter = ::Nanoc::Filters::BlueCloth.new
# Run filter
result = filter.setup_and_run('> Quote')
assert_match %r{\s*Quote
\s*
}, result
end
end
nanoc-4.11.0/nanoc/test/filters/test_coffeescript.rb000066400000000000000000000006361340050175000224600ustar00rootroot00000000000000# frozen_string_literal: true
require 'helper'
class Nanoc::Filters::CoffeeScriptTest < Nanoc::TestCase
def test_filter
if_have 'coffee-script' do
# Create filter
filter = ::Nanoc::Filters::CoffeeScript.new
# Run filter (no assigns)
result = filter.setup_and_run('alert 42')
assert_equal('(function() { alert(42); }).call(this); ', result.gsub(/\s+/, ' '))
end
end
end
nanoc-4.11.0/nanoc/test/filters/test_erubi.rb000066400000000000000000000051151340050175000211070ustar00rootroot00000000000000# frozen_string_literal: true
require 'helper'
class Nanoc::Filters::ErubiTest < Nanoc::TestCase
def test_filter_with_instance_variable
# Create filter
filter = ::Nanoc::Filters::Erubi.new(location: 'a cheap motel')
# Run filter
result = filter.setup_and_run('<%= "I was hiding in #{@location}." %>') # rubocop:disable Lint/InterpolationCheck
assert_equal('I was hiding in a cheap motel.', result)
end
def test_filter_with_instance_method
# Create filter
filter = ::Nanoc::Filters::Erubi.new(location: 'a cheap motel')
# Run filter
result = filter.setup_and_run('<%= "I was hiding in #{location}." %>') # rubocop:disable Lint/InterpolationCheck
assert_equal('I was hiding in a cheap motel.', result)
end
def test_filter_syntax_error
# Create filter
item = Nanoc::Int::Item.new('asdf', {}, '/about.md')
item_rep = Nanoc::Int::ItemRep.new(item, :xml)
filter = ::Nanoc::Filters::Erubi.new(item: item, item_rep: item_rep)
# Run filter
raised = false
begin
filter.setup_and_run('<%= this isn\'t really ruby so it\'ll break, muahaha %>')
rescue SyntaxError => e
assert_match('item /about.md (rep xml):1: syntax error, unexpected tIDENTIFIER', e.to_s)
assert_match 'syntax error', e.message
raised = true
end
assert raised
end
def test_filter_regular_error
# Create filter
item = Nanoc::Int::Item.new('asdf', {}, '/about.md')
item_rep = Nanoc::Int::ItemRep.new(item, :xml)
filter = ::Nanoc::Filters::Erubi.new(item: item, item_rep: item_rep)
# Run filter
raised = false
begin
filter.setup_and_run('<%= undefined_method_2ff04e22 %>')
rescue => e
assert_match 'item /about.md (rep xml):1', e.backtrace.join("\n")
raised = true
end
assert raised
end
def test_filter_with_yield
# Create filter
filter = ::Nanoc::Filters::Erubi.new(content: 'a cheap motel')
# Run filter
result = filter.setup_and_run('<%= "I was hiding in #{yield}." %>') # rubocop:disable Lint/InterpolationCheck
assert_equal('I was hiding in a cheap motel.', result)
end
def test_filter_with_yield_without_content
# Create filter
filter = ::Nanoc::Filters::Erubi.new(location: 'a cheap motel')
# Run filter
assert_raises LocalJumpError do
filter.setup_and_run('<%= "I was hiding in #{yield}." %>') # rubocop:disable Lint/InterpolationCheck
end
end
def test_filter_with_erbout
filter = ::Nanoc::Filters::Erubi.new
result = filter.setup_and_run('stuff<% _erbout << _erbout %>')
assert_equal 'stuffstuff', result
end
end
nanoc-4.11.0/nanoc/test/filters/test_erubis.rb000066400000000000000000000036371340050175000213010ustar00rootroot00000000000000# frozen_string_literal: true
require 'helper'
class Nanoc::Filters::ErubisTest < Nanoc::TestCase
def test_filter_with_instance_variable
# Create filter
filter = ::Nanoc::Filters::Erubis.new(location: 'a cheap motel')
# Run filter
result = filter.setup_and_run('<%= "I was hiding in #{@location}." %>') # rubocop:disable Lint/InterpolationCheck
assert_equal('I was hiding in a cheap motel.', result)
end
def test_filter_with_instance_method
# Create filter
filter = ::Nanoc::Filters::Erubis.new(location: 'a cheap motel')
# Run filter
result = filter.setup_and_run('<%= "I was hiding in #{location}." %>') # rubocop:disable Lint/InterpolationCheck
assert_equal('I was hiding in a cheap motel.', result)
end
def test_filter_error
# Create filter
filter = ::Nanoc::Filters::Erubis.new
# Run filter
raised = false
begin
filter.setup_and_run('<%= this isn\'t really ruby so it\'ll break, muahaha %>')
rescue SyntaxError => e
e.message =~ /(.+?):\d+: /
assert_match '?', Regexp.last_match[1]
raised = true
end
assert raised
end
def test_filter_with_yield
# Create filter
filter = ::Nanoc::Filters::Erubis.new(content: 'a cheap motel')
# Run filter
result = filter.setup_and_run('<%= "I was hiding in #{yield}." %>') # rubocop:disable Lint/InterpolationCheck
assert_equal('I was hiding in a cheap motel.', result)
end
def test_filter_with_yield_without_content
# Create filter
filter = ::Nanoc::Filters::Erubis.new(location: 'a cheap motel')
# Run filter
assert_raises LocalJumpError do
filter.setup_and_run('<%= "I was hiding in #{yield}." %>') # rubocop:disable Lint/InterpolationCheck
end
end
def test_filter_with_erbout
filter = ::Nanoc::Filters::Erubis.new
result = filter.setup_and_run('stuff<% _erbout << _erbout %>')
assert_equal 'stuffstuff', result
end
end
nanoc-4.11.0/nanoc/test/filters/test_haml.rb000066400000000000000000000043451340050175000207260ustar00rootroot00000000000000# frozen_string_literal: true
require 'helper'
class Nanoc::Filters::HamlTest < Nanoc::TestCase
def test_filter
# Create filter
filter = ::Nanoc::Filters::Haml.new(question: 'Is this the Payne residence?')
# Run filter (no assigns)
result = filter.setup_and_run('%html')
assert_match(/.*<\/html>/, result)
# Run filter (assigns without @)
result = filter.setup_and_run('%p= question')
assert_equal("Is this the Payne residence?
\n", result)
# Run filter (assigns with @)
result = filter.setup_and_run('%p= @question')
assert_equal("Is this the Payne residence?
\n", result)
end
def test_filter_with_params
# Create filter
filter = ::Nanoc::Filters::Haml.new(foo: 'bar')
# Check with HTML5
result = filter.setup_and_run('%img', format: :html5)
assert_match(/
/, result)
# Check with XHTML
result = filter.setup_and_run('%img', format: :xhtml)
assert_match(/
/, result)
end
def test_filter_error
# Create filter
filter = ::Nanoc::Filters::Haml.new(foo: 'bar')
# Run filter
raised = false
begin
filter.setup_and_run('%p= this isn\'t really ruby so it\'ll break, muahaha')
rescue SyntaxError, Haml::SyntaxError => e
e.message =~ /(.+?):\d+: /
assert_match '?', Regexp.last_match[1]
raised = true
end
assert raised
end
def test_filter_with_yield
# Create filter
filter = ::Nanoc::Filters::Haml.new(content: 'Is this the Payne residence?')
# Run filter
result = filter.setup_and_run('%p= yield')
assert_equal("Is this the Payne residence?
\n", result)
end
def test_filter_with_yield_without_content
# Create filter
filter = ::Nanoc::Filters::Haml.new(location: 'Is this the Payne residence?')
# Run filter
assert_raises LocalJumpError do
filter.setup_and_run('%p= yield')
end
end
def test_filter_with_proper_indentation
# Create file to include
File.open('stuff', 'w') do |io|
io.write("Max Payne\nMona Sax
")
end
# Run filter
filter = ::Nanoc::Filters::Haml.new
result = filter.setup_and_run("%body\n ~ File.read('stuff')")
assert_match(/Max Payne
Mona Sax/, result)
end
end
nanoc-4.11.0/nanoc/test/filters/test_handlebars.rb000066400000000000000000000034221340050175000221030ustar00rootroot00000000000000# frozen_string_literal: true
require 'helper'
class Nanoc::Filters::HandlebarsTest < Nanoc::TestCase
def test_filter
if_have 'handlebars' do
# Create data
item = Nanoc::Int::Item.new(
'content',
{ title: 'Max Payne', protagonist: 'Max Payne', location: 'here' },
'/games/max-payne',
)
layout = Nanoc::Int::Layout.new(
'layout content',
{ name: 'Max Payne' },
'/default',
)
config = { animals: 'cats and dogs' }
# Create filter
assigns = {
item: item,
layout: layout,
config: config,
content: 'No Payne No Gayne',
}
filter = ::Nanoc::Filters::Handlebars.new(assigns)
# Run filter
result = filter.setup_and_run('{{protagonist}} says: {{yield}}.')
assert_equal('Max Payne says: No Payne No Gayne.', result)
result = filter.setup_and_run('We can’t stop {{item.location}}! This is the {{layout.name}} layout!')
assert_equal('We can’t stop here! This is the Max Payne layout!', result)
result = filter.setup_and_run('It’s raining {{config.animals}} here!')
assert_equal('It’s raining cats and dogs here!', result)
end
end
def test_filter_without_layout
if_have 'handlebars' do
# Create data
item = Nanoc::Int::Item.new(
'content',
{ title: 'Max Payne', protagonist: 'Max Payne', location: 'here' },
'/games/max-payne',
)
# Create filter
assigns = {
item: item,
content: 'No Payne No Gayne',
}
filter = ::Nanoc::Filters::Handlebars.new(assigns)
# Run filter
result = filter.setup_and_run('{{protagonist}} says: {{yield}}.')
assert_equal('Max Payne says: No Payne No Gayne.', result)
end
end
end
nanoc-4.11.0/nanoc/test/filters/test_kramdown.rb000066400000000000000000000032651340050175000216270ustar00rootroot00000000000000# frozen_string_literal: true
require 'helper'
class Nanoc::Filters::KramdownTest < Nanoc::TestCase
def test_filter
# Create filter
filter = ::Nanoc::Filters::Kramdown.new
# Run filter
result = filter.setup_and_run('This is _so_ **cool**!')
assert_equal("This is so cool!
\n", result)
end
def test_warnings
# Create item
item = Nanoc::Int::Item.new('foo', {}, '/foo.md')
item_view = Nanoc::CompilationItemView.new(item, nil)
item_rep = Nanoc::Int::ItemRep.new(item, :default)
item_rep_view = Nanoc::CompilationItemRepView.new(item_rep, nil)
# Create filter
filter = ::Nanoc::Filters::Kramdown.new(item: item_view, item_rep: item_rep_view)
# Run filter
io = capturing_stdio do
filter.setup_and_run('{:foo}this is bogus')
end
assert_empty io[:stdout]
assert_equal "kramdown warning(s) for #{item_rep_view.inspect}\n Found span IAL after text - ignoring it\n", io[:stderr]
end
def test_warning_filters
# Create item
item = Nanoc::Int::Item.new('foo', {}, '/foo.md')
item_view = Nanoc::CompilationItemView.new(item, nil)
item_rep = Nanoc::Int::ItemRep.new(item, :default)
item_rep_view = Nanoc::CompilationItemRepView.new(item_rep, nil)
# Create filter
filter = ::Nanoc::Filters::Kramdown.new(item: item_view, item_rep: item_rep_view)
# Run filter
io = capturing_stdio do
filter.setup_and_run("{:foo}this is bogus\n[foo]: http://foo.com\n", warning_filters: 'No link definition')
end
assert_empty io[:stdout]
assert_equal "kramdown warning(s) for #{item_rep_view.inspect}\n Found span IAL after text - ignoring it\n", io[:stderr]
end
end
nanoc-4.11.0/nanoc/test/filters/test_markaby.rb000066400000000000000000000004561340050175000214320ustar00rootroot00000000000000# frozen_string_literal: true
require 'helper'
class Nanoc::Filters::MarkabyTest < Nanoc::TestCase
def test_filter
# Create filter
filter = ::Nanoc::Filters::Markaby.new
# Run filter
result = filter.setup_and_run("html do\nend")
assert_equal('', result)
end
end
nanoc-4.11.0/nanoc/test/filters/test_maruku.rb000066400000000000000000000005261340050175000213060ustar00rootroot00000000000000# frozen_string_literal: true
require 'helper'
class Nanoc::Filters::MarukuTest < Nanoc::TestCase
def test_filter
# Create filter
filter = ::Nanoc::Filters::Maruku.new
# Run filter
result = filter.setup_and_run('This is _so_ *cool*!')
assert_equal('This is so cool!
', result.strip)
end
end
nanoc-4.11.0/nanoc/test/filters/test_mustache.rb000066400000000000000000000017271340050175000216170ustar00rootroot00000000000000# frozen_string_literal: true
require 'helper'
class Nanoc::Filters::MustacheTest < Nanoc::TestCase
def test_filter
# Create item
item = Nanoc::Int::Item.new(
'content',
{ title: 'Max Payne', protagonist: 'Max Payne' },
'/games/max-payne',
)
# Create filter
filter = ::Nanoc::Filters::Mustache.new(item: item)
# Run filter
result = filter.setup_and_run('The protagonist of {{title}} is {{protagonist}}.')
assert_equal('The protagonist of Max Payne is Max Payne.', result)
end
def test_filter_with_yield
# Create item
item = Nanoc::Int::Item.new(
'content',
{ title: 'Max Payne', protagonist: 'Max Payne' },
'/games/max-payne',
)
# Create filter
filter = ::Nanoc::Filters::Mustache.new(
content: 'No Payne No Gayne', item: item,
)
# Run filter
result = filter.setup_and_run('Max says: {{yield}}.')
assert_equal('Max says: No Payne No Gayne.', result)
end
end
nanoc-4.11.0/nanoc/test/filters/test_pandoc.rb000066400000000000000000000022611340050175000212440ustar00rootroot00000000000000# frozen_string_literal: true
require 'helper'
class Nanoc::Filters::PandocTest < Nanoc::TestCase
def test_filter
if_have 'pandoc-ruby' do
skip_unless_have_command 'pandoc'
# Create filter
filter = ::Nanoc::Filters::Pandoc.new
# Run filter
result = filter.setup_and_run("# Heading\n")
assert_match(%r{Heading
\s*}, result)
end
end
def test_params_old
if_have 'pandoc-ruby' do
skip_unless_have_command 'pandoc'
# Create filter
filter = ::Nanoc::Filters::Pandoc.new
# Run filter
args = { f: :markdown, to: :html }
result = filter.setup_and_run("# Heading\n", args)
assert_match(%r{Heading
\s*}, result)
end
end
def test_params_new
if_have 'pandoc-ruby' do
skip_unless_have_command 'pandoc'
# Create filter
filter = ::Nanoc::Filters::Pandoc.new
# Run filter
args = [:s, { f: :markdown, to: :html }, 'wrap=none', :toc]
result = filter.setup_and_run("# Heading\n", args: args)
assert_match '