From 330005d932c203e3465703c6aabb2993dbed7aec Mon Sep 17 00:00:00 2001 From: Parker Moore Date: Wed, 16 Apr 2014 16:42:01 -0400 Subject: [PATCH 01/15] Reset the collections hash on #reset. Fixes #2234. --- lib/jekyll/site.rb | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/jekyll/site.rb b/lib/jekyll/site.rb index 51d2be5a..1ca0349b 100644 --- a/lib/jekyll/site.rb +++ b/lib/jekyll/site.rb @@ -55,6 +55,7 @@ module Jekyll self.pages = [] self.static_files = [] self.data = {} + @collections = {} if limit_posts < 0 raise ArgumentError, "limit_posts must be a non-negative number" From fd98d5b1e694dfbbf2e8524ee3067ece8257a1ee Mon Sep 17 00:00:00 2001 From: Parker Moore Date: Wed, 23 Apr 2014 14:00:13 -0400 Subject: [PATCH 02/15] Fetch collection names agnostically regarding the data structure of config['collections'] --- lib/jekyll/site.rb | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/lib/jekyll/site.rb b/lib/jekyll/site.rb index 1ca0349b..9a937220 100644 --- a/lib/jekyll/site.rb +++ b/lib/jekyll/site.rb @@ -91,10 +91,23 @@ module Jekyll # # Returns a Hash containing collection name-to-instance pairs. def collections - @collections ||= if config['collections'] - Hash[config['collections'].map { |coll| [coll, Jekyll::Collection.new(self, coll)] } ] + @collections ||= Hash[collection_names.map { |coll| [coll, Jekyll::Collection.new(self, coll)] } ] + end + + # The list of collection names. + # + # Returns an array of collection names from the configuration, + # or an empty array if the `collections` key is not set. + def collection_names + case config['collections'] + when Hash + config['collections'].keys + when Array + config['collections'] + when nil + [] else - Hash.new + raise ArgumentError, "Your `collections` key must be a hash or an array." end end From a27e5825b9868c909a0fde040d0d64bbab306e9b Mon Sep 17 00:00:00 2001 From: Parker Moore Date: Thu, 24 Apr 2014 12:16:39 -0400 Subject: [PATCH 03/15] Nil-out `@collections` so `#collections` will re-compile --- lib/jekyll/site.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/jekyll/site.rb b/lib/jekyll/site.rb index 9a937220..4cef61a8 100644 --- a/lib/jekyll/site.rb +++ b/lib/jekyll/site.rb @@ -55,7 +55,7 @@ module Jekyll self.pages = [] self.static_files = [] self.data = {} - @collections = {} + @collections = nil if limit_posts < 0 raise ArgumentError, "limit_posts must be a non-negative number" From f1a422dfffb98e12349dbf0e2cc2ca47f0afaaa5 Mon Sep 17 00:00:00 2001 From: Parker Moore Date: Thu, 24 Apr 2014 12:16:50 -0400 Subject: [PATCH 04/15] Don't pretend there is a collections setter --- lib/jekyll/site.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/jekyll/site.rb b/lib/jekyll/site.rb index 4cef61a8..88c96e1e 100644 --- a/lib/jekyll/site.rb +++ b/lib/jekyll/site.rb @@ -4,7 +4,7 @@ module Jekyll :exclude, :include, :source, :dest, :lsi, :highlighter, :permalink_style, :time, :future, :unpublished, :safe, :plugins, :limit_posts, :show_drafts, :keep_files, :baseurl, :data, :file_read_opts, :gems, - :plugin_manager, :collections + :plugin_manager attr_accessor :converters, :generators From 7be78de93a272db1e01b40691edb5f7a18f75d43 Mon Sep 17 00:00:00 2001 From: Parker Moore Date: Thu, 24 Apr 2014 12:17:00 -0400 Subject: [PATCH 05/15] Don't read the collection if it's the data collection --- lib/jekyll/site.rb | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/lib/jekyll/site.rb b/lib/jekyll/site.rb index 88c96e1e..7a7a27f5 100644 --- a/lib/jekyll/site.rb +++ b/lib/jekyll/site.rb @@ -220,7 +220,9 @@ module Jekyll # # Returns nothing. def read_collections - collections.each { |_, collection| collection.read } + collections.each do |_, collection| + collection.read unless collection.label.eql?("data") + end end # Run each of the Generators. From 3a6ad0737cededaa6f2cfd0866d06d75f3249261 Mon Sep 17 00:00:00 2001 From: Parker Moore Date: Thu, 24 Apr 2014 12:17:18 -0400 Subject: [PATCH 06/15] Add a script/test file for :heart: and :money: --- script/test | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100755 script/test diff --git a/script/test b/script/test new file mode 100755 index 00000000..793f0de7 --- /dev/null +++ b/script/test @@ -0,0 +1,11 @@ +#! /bin/bash + +set -x + +if [ -z "$1" ]; then + TEST_FILES="test/test*.rb" +else + TEST_FILES="$@" +fi + +/usr/bin/env ruby -I"lib:test" -r rake -r rake/rake_test_loader ${TEST_FILES} From 0dc680df0b0ec57a16d8dfd024254b37a3ad2f8f Mon Sep 17 00:00:00 2001 From: Parker Moore Date: Thu, 24 Apr 2014 12:50:08 -0400 Subject: [PATCH 07/15] Always render collections, just don't always write them --- lib/jekyll/document.rb | 18 +++++++++++------- lib/jekyll/site.rb | 17 +++++------------ test/test_collections.rb | 19 +++++++++++++++++++ 3 files changed, 35 insertions(+), 19 deletions(-) diff --git a/lib/jekyll/document.rb b/lib/jekyll/document.rb index ed200511..0a75fe96 100644 --- a/lib/jekyll/document.rb +++ b/lib/jekyll/document.rb @@ -112,7 +112,7 @@ module Jekyll # # Returns the permalink or nil if no permalink was set in the data. def permalink - data && data['permalink'] + data && data.is_a?(Hash) && data['permalink'] end # The computed URL for the document. See `Jekyll::URL#to_s` for more details. @@ -192,12 +192,16 @@ module Jekyll # # Returns a Hash representing this Document's data. def to_liquid - Utils.deep_merge_hashes data, { - "content" => content, - "path" => path, - "relative_path" => relative_path, - "url" => url - } + if data.is_a?(Hash) + Utils.deep_merge_hashes data, { + "content" => content, + "path" => path, + "relative_path" => relative_path, + "url" => url + } + else + data + end end # The inspect string for this document. diff --git a/lib/jekyll/site.rb b/lib/jekyll/site.rb index 7a7a27f5..0d6f80fc 100644 --- a/lib/jekyll/site.rb +++ b/lib/jekyll/site.rb @@ -111,13 +111,6 @@ module Jekyll end end - # The list of collections to render. - # - # The array of collection labels to render. - def to_render - @to_render ||= (config['render'] || Array.new) - end - # Read Site data from disk and load it into internal data structures. # # Returns nothing. @@ -240,8 +233,8 @@ module Jekyll def render relative_permalinks_deprecation_method - to_render.each do |label| - collections[label].docs.each do |document| + collections.each do |label, collection| + collection.docs.each do |document| document.output = Jekyll::Renderer.new(self, document).run end end @@ -411,9 +404,9 @@ module Jekyll end def documents - collections.reduce(Set.new) do |docs, (label, coll)| - if to_render.include?(label) - docs.merge(coll.docs) + collections.reduce(Set.new) do |docs, (_, collection)| + if collection.write? + docs.merge(collection.docs) else docs end diff --git a/test/test_collections.rb b/test/test_collections.rb index 8b4c2d23..b6fd41d5 100644 --- a/test/test_collections.rb +++ b/test/test_collections.rb @@ -107,6 +107,25 @@ class TestCollections < Test::Unit::TestCase end end + context "with a collection with metadata" do + setup do + @site = fixture_site({ + "collections" => { + "methods" => { + "foo" => "bar", + "baz" => "whoo" + } + } + }) + @site.process + @collection = @site.collections["methods"] + end + + should "extract the configuration collection information as metadata" do + assert_equal @collection.metadata, {"foo" => "bar", "baz" => "whoo"} + end + end + context "in safe mode" do setup do @site = fixture_site({ From b74c90dc20ee0604f54198235122606afc2d3090 Mon Sep 17 00:00:00 2001 From: Parker Moore Date: Thu, 24 Apr 2014 12:50:32 -0400 Subject: [PATCH 08/15] Extract Collections metadata from site config --- lib/jekyll/collection.rb | 26 +++++++++++++++++++++++--- 1 file changed, 23 insertions(+), 3 deletions(-) diff --git a/lib/jekyll/collection.rb b/lib/jekyll/collection.rb index ad0e5fa5..f9bf1e8b 100644 --- a/lib/jekyll/collection.rb +++ b/lib/jekyll/collection.rb @@ -1,6 +1,6 @@ module Jekyll class Collection - attr_reader :site, :label + attr_reader :site, :label, :metadata # Create a new Collection. # @@ -9,8 +9,9 @@ module Jekyll # # Returns nothing. def initialize(site, label) - @site = site - @label = sanitize_label(label) + @site = site + @label = sanitize_label(label) + @metadata = extract_metadata end # Fetch the Documents in this collection. @@ -117,5 +118,24 @@ module Jekyll docs end + # Whether the collection's documents ought to be written as individual + # files in the output. + # + # Returns true if the 'write' metadata is true, false otherwise. + def write? + !!metadata['write'] + end + + # Extract options for this collection from the site configuration. + # + # Returns the metadata for this collection + def extract_metadata + if site.config['collections'].is_a?(Hash) + site.config['collections'][label] || {} + else + {} + end + end + end end From 764dc8883288173f2339c5159c632ab127b81a22 Mon Sep 17 00:00:00 2001 From: Parker Moore Date: Thu, 24 Apr 2014 13:29:45 -0400 Subject: [PATCH 09/15] script/test should probably use bundler --- script/test | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/script/test b/script/test index 793f0de7..78e6866a 100755 --- a/script/test +++ b/script/test @@ -8,4 +8,4 @@ else TEST_FILES="$@" fi -/usr/bin/env ruby -I"lib:test" -r rake -r rake/rake_test_loader ${TEST_FILES} +/usr/bin/env bundle exec ruby -I"lib:test" -r rake -r rake/rake_test_loader ${TEST_FILES} From fb39b41ffb4c596e31cdc6f11d6e58bda250403d Mon Sep 17 00:00:00 2001 From: Parker Moore Date: Thu, 24 Apr 2014 13:29:54 -0400 Subject: [PATCH 10/15] NO MORE DATA COLLECTION I CAN'T HANDLE IT --- lib/jekyll/site.rb | 19 ++++++++++--------- test/test_collections.rb | 6 ++---- 2 files changed, 12 insertions(+), 13 deletions(-) diff --git a/lib/jekyll/site.rb b/lib/jekyll/site.rb index 0d6f80fc..4f3d04fe 100644 --- a/lib/jekyll/site.rb +++ b/lib/jekyll/site.rb @@ -195,17 +195,18 @@ module Jekyll # # Returns nothing def read_data(dir) - unless dir.to_s.eql?("_data") - Jekyll.logger.error "Error:", "Data source directories other than '_data' have been removed.\n" + - "Please move your YAML files to `_data` and remove the `data_source` key from your `_config.yml`." - end + base = File.join(source, dir) + return unless File.directory?(base) && (!safe || !File.symlink?(base)) - collections['data'] = Jekyll::Collection.new(self, "data") - collections['data'].read + entries = Dir.chdir(base) { Dir['*.{yaml,yml}'] } + entries.delete_if { |e| File.directory?(File.join(base, e)) } - collections['data'].docs.each do |doc| - key = sanitize_filename(doc.basename(".*")) - self.data[key] = doc.data + entries.each do |entry| + path = File.join(source, dir, entry) + next if File.symlink?(path) && safe + + key = sanitize_filename(File.basename(entry, '.*')) + self.data[key] = SafeYAML.load_file(path) end end diff --git a/test/test_collections.rb b/test/test_collections.rb index b6fd41d5..8dbc397d 100644 --- a/test/test_collections.rb +++ b/test/test_collections.rb @@ -57,10 +57,8 @@ class TestCollections < Test::Unit::TestCase @site.process end - should "not contain any collections other than the default ones" do - collections = @site.collections.dup - assert collections.delete("data").is_a?(Jekyll::Collection) - assert_equal Hash.new, collections + should "not contain any collections" do + assert_equal Hash.new, @site.collections end end From dd4fe87f69e04025517ee7f403754d87a07ff0fe Mon Sep 17 00:00:00 2001 From: Parker Moore Date: Thu, 24 Apr 2014 13:30:13 -0400 Subject: [PATCH 11/15] Use Hash.new instead of hash literal --- lib/jekyll/collection.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/jekyll/collection.rb b/lib/jekyll/collection.rb index f9bf1e8b..be590e0d 100644 --- a/lib/jekyll/collection.rb +++ b/lib/jekyll/collection.rb @@ -131,7 +131,7 @@ module Jekyll # Returns the metadata for this collection def extract_metadata if site.config['collections'].is_a?(Hash) - site.config['collections'][label] || {} + site.config['collections'][label] || Hash.new else {} end From c906dfdf713fa07f3a45b2026111233c362b5e1c Mon Sep 17 00:00:00 2001 From: Parker Moore Date: Thu, 24 Apr 2014 13:59:11 -0400 Subject: [PATCH 12/15] TEST THE COLLECTIONS --- features/collections.feature | 44 ++++++++++++++++++++++++++---------- lib/jekyll/collection.rb | 8 ++++++- lib/jekyll/site.rb | 3 ++- 3 files changed, 41 insertions(+), 14 deletions(-) diff --git a/features/collections.feature b/features/collections.feature index 6ff41080..6e8d76a8 100644 --- a/features/collections.feature +++ b/features/collections.feature @@ -9,30 +9,50 @@ Feature: Collections And I have a configuration file with "collections" set to "['methods']" When I run jekyll build Then the _site directory should exist - And I should see "Collections: Use `{{ page.title }}` to build a full configuration for use w/Jekyll.\n\nWhatever: {{ page.whatever }}\n`{{ page.title }}` is used to make sure your path is in your source.\nRun your generators! {{ page.layout }}\nCreate dat site.\nRun your generators! {{ page.layout }}" in "_site/index.html" + And I should see "Collections:

Use Jekyll.configuration to build a full configuration for use w/Jekyll.

\n\n

Whatever: foo.bar

\n

Jekyll.sanitized_path is used to make sure your path is in your source.

\n

Run your generators! default

\n

Create dat site.

\n

Run your generators! default

" in "_site/index.html" + And the "_site/methods/configuration.html" file should not exist Scenario: Rendered collection Given I have an "index.html" page that contains "Collections: {{ site.collections }}" + And I have an "collection_metadata.html" page that contains "Methods metadata: {{ site.collections.methods.foo }} {{ site.collections.methods }}" And I have fixture collections - And I have a configuration file with: - | key | value | - | collections | ['methods'] | - | render | ['methods'] | + And I have a "_config.yml" file with content: + """ + collections: + methods: + write: true + foo: bar + """ When I run jekyll build Then the _site directory should exist - And I should see "Collections: methods" in "_site/index.html" + And I should see "Collections: {\"methods" in "_site/index.html" + And I should see "Methods metadata: bar" in "_site/collection_metadata.html" And I should see "

Whatever: foo.bar

" in "_site/methods/configuration.html" Scenario: Rendered document in a layout Given I have an "index.html" page that contains "Collections: {{ site.collections }}" And I have a default layout that contains "
Tom Preston-Werner
{{content}}" And I have fixture collections - And I have a configuration file with: - | key | value | - | collections | ['methods'] | - | render | ['methods'] | + And I have a "_config.yml" file with content: + """ + collections: + methods: + write: true + foo: bar + """ When I run jekyll build Then the _site directory should exist - And I should see "Collections: methods" in "_site/index.html" + And I should see "Collections: {\"methods" in "_site/index.html" And I should see "

Run your generators! default

" in "_site/methods/site/generate.html" - And I should see "
Tom Preston-Werner
" in "_site/methods/site/generate.html" \ No newline at end of file + And I should see "
Tom Preston-Werner
" in "_site/methods/site/generate.html" + + Scenario: Collections directly on the site + Given I have an "index.html" page that contains "Collections: {% for method in site.methods %}{{ method.relative_path }} {% endfor %}" + And I have fixture collections + And I have a "_config.yml" file with content: + """ + collections: [methods] + """ + When I run jekyll + Then the _site directory should exist + And I should see "Collections: _methods/configuration.md _methods/sanitized_path.md _methods/site/generate.md _methods/site/initialize.md _methods/um_hi.md" in "_site/index.html" diff --git a/lib/jekyll/collection.rb b/lib/jekyll/collection.rb index be590e0d..ba8f8d91 100644 --- a/lib/jekyll/collection.rb +++ b/lib/jekyll/collection.rb @@ -115,7 +115,13 @@ module Jekyll # # Returns a representation of this collection for use in Liquid. def to_liquid - docs + metadata.merge({ + "label" => label, + "docs" => docs, + "directory" => directory, + "written" => write?, + "relative_directory" => relative_directory + }) end # Whether the collection's documents ought to be written as individual diff --git a/lib/jekyll/site.rb b/lib/jekyll/site.rb index 4f3d04fe..ccc6d2c6 100644 --- a/lib/jekyll/site.rb +++ b/lib/jekyll/site.rb @@ -316,7 +316,7 @@ module Jekyll def site_payload {"jekyll" => { "version" => Jekyll::VERSION }, "site" => Utils.deep_merge_hashes(config, - Utils.deep_merge_hashes(collections, { + Utils.deep_merge_hashes(Hash[collections.map{|label, coll| [label, coll.docs]}], { "time" => time, "posts" => posts.sort { |a, b| b <=> a }, "pages" => pages, @@ -324,6 +324,7 @@ module Jekyll "html_pages" => pages.reject { |page| !page.html? }, "categories" => post_attr_hash('categories'), "tags" => post_attr_hash('tags'), + "collections" => collections, "data" => site_data })) } From d2b1d538bf402809753c981548a9ec8f6c7b7b44 Mon Sep 17 00:00:00 2001 From: Parker Moore Date: Thu, 24 Apr 2014 14:07:08 -0400 Subject: [PATCH 13/15] Add test for collections' new #to_liquid sturff --- test/test_collections.rb | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/test/test_collections.rb b/test/test_collections.rb index 8dbc397d..dafc2a8f 100644 --- a/test/test_collections.rb +++ b/test/test_collections.rb @@ -49,6 +49,35 @@ class TestCollections < Test::Unit::TestCase should "know the full path to itself on the filesystem" do assert_equal @collection.directory, source_dir("_methods") end + + context "when turned into Liquid" do + should "have a label attribute" do + assert_equal @collection.to_liquid["label"], "methods" + end + + should "have a docs attribute" do + assert_equal @collection.to_liquid["docs"], Array.new + end + + should "have a directory attribute" do + assert_equal @collection.to_liquid["directory"], source_dir("_methods") + end + + should "have a relative_directory attribute" do + assert_equal @collection.to_liquid["relative_directory"], "_methods" + end + + should "have a written attribute" do + assert_equal @collection.to_liquid["written"], false + end + end + + should "know whether it should be written or not" do + assert_equal @collection.write?, false + @collection.metadata['write'] = true + assert_equal @collection.write?, true + @collection.metadata.delete 'write' + end end context "with no collections specified" do From 2ccf7f1cfbce397fcfdd7841257a8cb8bf692224 Mon Sep 17 00:00:00 2001 From: Parker Moore Date: Fri, 25 Apr 2014 13:04:56 -0400 Subject: [PATCH 14/15] Run jekyll build in features (must give subcommand) --- features/collections.feature | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/features/collections.feature b/features/collections.feature index 6e8d76a8..5384a9c7 100644 --- a/features/collections.feature +++ b/features/collections.feature @@ -51,8 +51,9 @@ Feature: Collections And I have fixture collections And I have a "_config.yml" file with content: """ - collections: [methods] + collections: + - methods """ - When I run jekyll + When I run jekyll build Then the _site directory should exist And I should see "Collections: _methods/configuration.md _methods/sanitized_path.md _methods/site/generate.md _methods/site/initialize.md _methods/um_hi.md" in "_site/index.html" From 622507309513f5a4102ef96c0959416eba888596 Mon Sep 17 00:00:00 2001 From: Parker Moore Date: Fri, 25 Apr 2014 19:47:35 -0400 Subject: [PATCH 15/15] Use the 'output' key instead of 'write' for writing out collections' document files. --- features/collections.feature | 19 ++++++++++++++++--- lib/jekyll/collection.rb | 2 +- test/test_collections.rb | 4 ++-- 3 files changed, 19 insertions(+), 6 deletions(-) diff --git a/features/collections.feature b/features/collections.feature index 5384a9c7..32e9161c 100644 --- a/features/collections.feature +++ b/features/collections.feature @@ -20,7 +20,7 @@ Feature: Collections """ collections: methods: - write: true + output: true foo: bar """ When I run jekyll build @@ -37,7 +37,7 @@ Feature: Collections """ collections: methods: - write: true + output: true foo: bar """ When I run jekyll build @@ -46,7 +46,7 @@ Feature: Collections And I should see "

Run your generators! default

" in "_site/methods/site/generate.html" And I should see "
Tom Preston-Werner
" in "_site/methods/site/generate.html" - Scenario: Collections directly on the site + Scenario: Collections specified as an array Given I have an "index.html" page that contains "Collections: {% for method in site.methods %}{{ method.relative_path }} {% endfor %}" And I have fixture collections And I have a "_config.yml" file with content: @@ -57,3 +57,16 @@ Feature: Collections When I run jekyll build Then the _site directory should exist And I should see "Collections: _methods/configuration.md _methods/sanitized_path.md _methods/site/generate.md _methods/site/initialize.md _methods/um_hi.md" in "_site/index.html" + + Scenario: Collections specified as an hash + Given I have an "index.html" page that contains "Collections: {% for method in site.methods %}{{ method.relative_path }} {% endfor %}" + And I have fixture collections + And I have a "_config.yml" file with content: + """ + collections: + methods: + baz: bin + """ + When I run jekyll build + Then the _site directory should exist + And I should see "Collections: _methods/configuration.md _methods/sanitized_path.md _methods/site/generate.md _methods/site/initialize.md _methods/um_hi.md" in "_site/index.html" diff --git a/lib/jekyll/collection.rb b/lib/jekyll/collection.rb index ba8f8d91..e5aead12 100644 --- a/lib/jekyll/collection.rb +++ b/lib/jekyll/collection.rb @@ -129,7 +129,7 @@ module Jekyll # # Returns true if the 'write' metadata is true, false otherwise. def write? - !!metadata['write'] + !!metadata['output'] end # Extract options for this collection from the site configuration. diff --git a/test/test_collections.rb b/test/test_collections.rb index dafc2a8f..3171b4fd 100644 --- a/test/test_collections.rb +++ b/test/test_collections.rb @@ -74,9 +74,9 @@ class TestCollections < Test::Unit::TestCase should "know whether it should be written or not" do assert_equal @collection.write?, false - @collection.metadata['write'] = true + @collection.metadata['output'] = true assert_equal @collection.write?, true - @collection.metadata.delete 'write' + @collection.metadata.delete 'output' end end