Skip to content
Permalink
Browse files

Make ItemArray more of a generic collection

An item collection is not inherently an array (it is not ordered). The
API now reflects this.
  • Loading branch information...
ddfreyne committed May 15, 2015
1 parent 623882e commit 5b92c4bb489fab88d3877ca5c4411135ab08a09f
@@ -177,7 +177,7 @@ def store
#
# @return [Nanoc::Int::DependencyTracker] The dependency tracker for this site
def dependency_tracker
dt = Nanoc::Int::DependencyTracker.new(@site.items + @site.layouts)
dt = Nanoc::Int::DependencyTracker.new(@site.items.to_a + @site.layouts)
dt.compiler = self
dt
end
@@ -197,7 +197,7 @@ def preprocess
#
# @api private
def objects
site.items + site.layouts + site.code_snippets +
site.items.to_a + site.layouts + site.code_snippets +
[site.config, rules_collection]
end

@@ -9,17 +9,10 @@ class ItemArray

extend Forwardable

EXCLUDED_METHODS = [
:[], :at, :slice, :class, :singleton_class, :clone, :dup, :initialize_dup, :initialize_clone,
:freeze, :methods, :singleton_methods, :protected_methods, :private_methods, :public_methods,
:instance_variables, :instance_variable_get, :instance_variable_set, :instance_variable_defined?,
:instance_of?, :kind_of?, :is_a?, :tap, :send, :public_send, :respond_to?, :respond_to_missing?,
:extend, :display, :method, :public_method, :define_singleton_method, :object_id, :equal?,
:instance_eval, :instance_exec, :__send__, :__id__
]

DELEGATED_METHODS = (Array.instance_methods + Enumerable.instance_methods).map(&:to_sym) - EXCLUDED_METHODS
def_delegators :@items, *DELEGATED_METHODS
def_delegator :@items, :each
def_delegator :@items, :size
def_delegator :@items, :<<
def_delegator :@items, :concat

def initialize(config)
@config = config
@@ -33,23 +26,19 @@ def freeze
super
end

def [](*args)
if 1 == args.size && args.first.is_a?(String)
item_with_identifier(args.first) || item_matching_glob(args.first)
elsif 1 == args.size && args.first.is_a?(Regexp)
@items.select { |i| i.identifier.to_s =~ args.first }
def [](arg)
case arg
when String
item_with_identifier(arg) || item_matching_glob(arg)
when Regexp
@items.find { |i| i.identifier.to_s =~ arg }
else
@items[*args]
raise ArgumentError, "don’t know how to fetch items by #{arg.inspect}"
end
end
alias_method :slice, :[]

def at(arg)
if arg.is_a?(String)
item_with_identifier(arg)
else
@items[arg]
end
def to_a
@items
end

protected
@@ -36,18 +36,6 @@ def size
@items.size
end

# Finds the item whose identifier matches the given string.
#
# @param [String] arg
#
# @return [nil] if no item matches the string
#
# @return [Nanoc::ItemView] if an item was found
def at(arg)
item = @items.at(arg)
item && view_class.new(item)
end

# Finds all items whose identifier matches the given argument.
#
# @param [String, Regex] arg
@@ -82,12 +70,7 @@ def find_all(arg)
# @return [Nanoc::ItemView] if an item was found
def [](arg)
res = @items[arg]
case res
when nil
nil
else
view_class.new(res)
end
res && view_class.new(res)
end
end
end
@@ -1,21 +1,33 @@
# encoding: utf-8

describe Nanoc::ItemCollectionView do
let(:wrapped) { double(:wrapped) }
let(:view) { described_class.new(wrapped) }

let(:config) do
{ pattern_syntax: 'glob' }
end

describe '#unwrap' do
let(:wrapped) do
Nanoc::Int::ItemArray.new(config).tap do |arr|
arr << Nanoc::Int::Item.new('foo', {}, '/foo/')
arr << Nanoc::Int::Item.new('bar', {}, '/bar/')
arr << Nanoc::Int::Item.new('baz', {}, '/baz/')
end
end

subject { view.unwrap }

it { should equal(wrapped) }
end

describe '#each' do
let(:wrapped) do
[
Nanoc::Int::Item.new('foo', {}, '/foo/'),
Nanoc::Int::Item.new('bar', {}, '/bar/'),
Nanoc::Int::Item.new('baz', {}, '/baz/'),
]
Nanoc::Int::ItemArray.new(config).tap do |arr|
arr << Nanoc::Int::Item.new('foo', {}, '/foo/')
arr << Nanoc::Int::Item.new('bar', {}, '/bar/')
arr << Nanoc::Int::Item.new('baz', {}, '/baz/')
end
end

it 'returns self' do
@@ -25,79 +37,81 @@

describe '#size' do
let(:wrapped) do
[
Nanoc::Int::Item.new('foo', {}, '/foo/'),
Nanoc::Int::Item.new('bar', {}, '/bar/'),
Nanoc::Int::Item.new('baz', {}, '/baz/'),
]
Nanoc::Int::ItemArray.new(config).tap do |arr|
arr << Nanoc::Int::Item.new('foo', {}, '/foo/')
arr << Nanoc::Int::Item.new('bar', {}, '/bar/')
arr << Nanoc::Int::Item.new('baz', {}, '/baz/')
end
end

subject { view.size }

it { should == 3 }
end

describe '#at' do
subject { view.at(arg) }

let(:arg) { 'some argument' }

context 'wrapped returns item' do
let(:item) { double(:item) }
describe '#[]' do
let(:page_item) { Nanoc::Int::Item.new('foo', {}, Nanoc::Identifier.new('/page.erb', style: :full)) }
let(:home_item) { Nanoc::Int::Item.new('bar', {}, Nanoc::Identifier.new('/home.erb', style: :full)) }

before do
expect(wrapped).to receive(:at).with(arg) { item }
let(:wrapped) do
Nanoc::Int::ItemArray.new(config).tap do |arr|
arr << page_item
arr << home_item
end
end

it 'returns a wrapped item' do
expect(subject.class).to equal(Nanoc::ItemView)
expect(subject.unwrap).to equal(item)
end
subject { view[arg] }

context 'no items found' do
let(:arg) { '/donkey.*' }
it { is_expected.to equal(nil) }
end

context 'wrapped returns nil' do
before do
expect(wrapped).to receive(:at).with(arg) { nil }
end
context 'direct identifier' do
let(:arg) { '/home.erb' }

it { should equal(nil) }
it 'returns wrapped item' do
expect(subject.class).to equal(Nanoc::ItemView)
expect(subject.unwrap).to equal(home_item)
end
end
end

describe '#[]' do
subject { view[arg] }
context 'glob' do
let(:arg) { '/home.*' }

let(:arg) { 'some argument' }
context 'globs not enabled' do
let(:config) { { pattern_syntax: nil } }

context 'wrapped returns nil' do
before do
expect(wrapped).to receive(:[]).with(arg) { nil }
it 'returns nil' do
expect(subject).to be_nil
end
end

it { should equal(nil) }
context 'globs enabled' do
it 'returns wrapped item' do
expect(subject.class).to equal(Nanoc::ItemView)
expect(subject.unwrap).to equal(home_item)
end
end
end

context 'wrapped returns item' do
let(:item) { double(:item) }

before do
expect(wrapped).to receive(:[]).with(arg) { item }
end
context 'regex' do
let(:arg) { %r{\A/home} }

it 'returns wrapped item' do
expect(subject.class).to equal(Nanoc::ItemView)
expect(subject.unwrap).to equal(item)
expect(subject.unwrap).to equal(home_item)
end
end
end

describe '#find_all' do
let(:wrapped) do
[
Nanoc::Int::Item.new('foo', {}, Nanoc::Identifier.new('/about.css', style: :full)),
Nanoc::Int::Item.new('bar', {}, Nanoc::Identifier.new('/about.md', style: :full)),
Nanoc::Int::Item.new('baz', {}, Nanoc::Identifier.new('/style.css', style: :full)),
]
Nanoc::Int::ItemArray.new(config).tap do |arr|
arr << Nanoc::Int::Item.new('foo', {}, Nanoc::Identifier.new('/about.css', style: :full))
arr << Nanoc::Int::Item.new('bar', {}, Nanoc::Identifier.new('/about.md', style: :full))
arr << Nanoc::Int::Item.new('baz', {}, Nanoc::Identifier.new('/style.css', style: :full))
end
end

subject { view.find_all(arg) }
@@ -55,5 +55,14 @@
expect(subject.unwrap).to equal(wrapped[1])
end
end

context 'regex' do
let(:arg) { %r{\A/home} }

it 'returns wrapped layout' do
expect(subject.class).to equal(Nanoc::LayoutView)
expect(subject.unwrap).to equal(wrapped[1])
end
end
end
end
@@ -306,7 +306,7 @@ def test_compile_should_recompile_all_reps

# At this point, even the already compiled items in the previous pass
# should have their compiled content assigned, so this should work:
site.items[0].reps[0].compiled_content
site.items['/index.*'].reps[0].compiled_content
end
end

0 comments on commit 5b92c4b

Please sign in to comment.
You can’t perform that action at this time.