diff --git a/jekyll.gemspec b/jekyll.gemspec index fc462f9f..473418fd 100644 --- a/jekyll.gemspec +++ b/jekyll.gemspec @@ -39,7 +39,7 @@ Gem::Specification.new do |s| s.add_runtime_dependency('redcarpet', "~> 3.1") s.add_runtime_dependency('toml', '~> 0.1.0') s.add_runtime_dependency('jekyll-coffeescript', '~> 1.0') - s.add_runtime_dependency('jekyll-sass-converter', '~> 1.0.0.rc1') + s.add_runtime_dependency('jekyll-sass-converter', '~> 1.0.0.rc3') s.add_development_dependency('rake', "~> 10.1") s.add_development_dependency('rdoc', "~> 3.11") diff --git a/lib/jekyll.rb b/lib/jekyll.rb index e4276967..7b661048 100644 --- a/lib/jekyll.rb +++ b/lib/jekyll.rb @@ -30,7 +30,7 @@ require 'toml' # internal requires require 'jekyll/version' -require 'jekyll/core_ext' +require 'jekyll/utils' require 'jekyll/stevenson' require 'jekyll/deprecator' require 'jekyll/configuration' @@ -83,7 +83,7 @@ module Jekyll config = config.read_config_files(config.config_files(override)) # Merge DEFAULTS < _config.yml < override - config = config.deep_merge(override).stringify_keys + config = Utils.deep_merge_hashes(config, override).stringify_keys set_timezone(config['timezone']) if config['timezone'] config diff --git a/lib/jekyll/configuration.rb b/lib/jekyll/configuration.rb index ad84f0b4..091bebc4 100644 --- a/lib/jekyll/configuration.rb +++ b/lib/jekyll/configuration.rb @@ -159,7 +159,7 @@ module Jekyll begin files.each do |config_file| new_config = read_config_file(config_file) - configuration = configuration.deep_merge(new_config) + configuration = Utils.deep_merge_hashes(configuration, new_config) end rescue ArgumentError => err Jekyll.logger.warn "WARNING:", "Error reading configuration. " + @@ -229,7 +229,7 @@ module Jekyll config[option] = csv_to_array(config[option]) end end - + if config.fetch('markdown', 'kramdown').to_s.downcase.eql?("maruku") Jekyll::Deprecator.deprecation_message "You're using the 'maruku' " + "Markdown processor. Maruku support has been deprecated and will " + diff --git a/lib/jekyll/converters/markdown/kramdown_parser.rb b/lib/jekyll/converters/markdown/kramdown_parser.rb index caeb5b65..cd1fdf9a 100644 --- a/lib/jekyll/converters/markdown/kramdown_parser.rb +++ b/lib/jekyll/converters/markdown/kramdown_parser.rb @@ -20,7 +20,7 @@ module Jekyll end end - Kramdown::Document.new(content, @config["kramdown"].symbolize_keys).to_html + Kramdown::Document.new(content, Utils.symbolize_hash_keys(@config["kramdown"])).to_html end end diff --git a/lib/jekyll/convertible.rb b/lib/jekyll/convertible.rb index 7761a3e9..bc87f336 100644 --- a/lib/jekyll/convertible.rb +++ b/lib/jekyll/convertible.rb @@ -107,7 +107,7 @@ module Jekyll further_data = Hash[(attrs || self.class::ATTRIBUTES_FOR_LIQUID).map { |attribute| [attribute, send(attribute)] }] - data.deep_merge(further_data) + Utils.deep_merge_hashes(data, further_data) end # Recursively render layouts @@ -123,7 +123,7 @@ module Jekyll used = Set.new([layout]) while layout - payload = payload.deep_merge({"content" => output, "page" => layout.data}) + payload = Utils.deep_merge_hashes(payload, {"content" => output, "page" => layout.data}) self.output = render_liquid(layout.content, payload, diff --git a/lib/jekyll/core_ext.rb b/lib/jekyll/core_ext.rb deleted file mode 100644 index 43edcb13..00000000 --- a/lib/jekyll/core_ext.rb +++ /dev/null @@ -1,55 +0,0 @@ -class Hash - # Merges self with another hash, recursively. - # - # This code was lovingly stolen from some random gem: - # http://gemjack.com/gems/tartan-0.1.1/classes/Hash.html - # - # Thanks to whoever made it. - def deep_merge(hash) - target = dup - - hash.keys.each do |key| - if hash[key].is_a? Hash and self[key].is_a? Hash - target[key] = target[key].deep_merge(hash[key]) - next - end - - target[key] = hash[key] - end - - target - end - - # Read array from the supplied hash favouring the singular key - # and then the plural key, and handling any nil entries. - # +hash+ the hash to read from - # +singular_key+ the singular key - # +plural_key+ the plural key - # - # Returns an array - def pluralized_array(singular_key, plural_key) - hash = self - if hash.has_key?(singular_key) - array = [hash[singular_key]] if hash[singular_key] - elsif hash.has_key?(plural_key) - case hash[plural_key] - when String - array = hash[plural_key].split - when Array - array = hash[plural_key].compact - end - end - array || [] - end - - def symbolize_keys! - keys.each do |key| - self[(key.to_sym rescue key) || key] = delete(key) - end - self - end - - def symbolize_keys - dup.symbolize_keys! - end -end diff --git a/lib/jekyll/page.rb b/lib/jekyll/page.rb index 6900e533..0c71c7d1 100644 --- a/lib/jekyll/page.rb +++ b/lib/jekyll/page.rb @@ -109,10 +109,10 @@ module Jekyll # # Returns nothing. def render(layouts, site_payload) - payload = { + payload = Utils.deep_merge_hashes({ "page" => to_liquid, 'paginator' => pager.to_liquid - }.deep_merge(site_payload) + }, site_payload) do_layout(payload, layouts) end diff --git a/lib/jekyll/post.rb b/lib/jekyll/post.rb index 58d1fc5f..180faa27 100644 --- a/lib/jekyll/post.rb +++ b/lib/jekyll/post.rb @@ -66,13 +66,13 @@ module Jekyll def populate_categories if categories.empty? - self.categories = data.pluralized_array('category', 'categories').map {|c| c.to_s.downcase} + self.categories = Utils.pluralized_array_from_hash(data, 'category', 'categories').map {|c| c.to_s.downcase} end categories.flatten! end def populate_tags - self.tags = data.pluralized_array("tag", "tags").flatten + self.tags = Utils.pluralized_array_from_hash(data, "tag", "tags").flatten end # Get the full path to the directory containing the post files @@ -241,10 +241,10 @@ module Jekyll # Returns nothing. def render(layouts, site_payload) # construct payload - payload = { + payload = Utils.deep_merge_hashes({ "site" => { "related_posts" => related_posts(site_payload["site"]["posts"]) }, "page" => to_liquid(EXCERPT_ATTRIBUTES_FOR_LIQUID) - }.deep_merge(site_payload) + }, site_payload) if generate_excerpt? extracted_excerpt.do_layout(payload, {}) diff --git a/lib/jekyll/utils.rb b/lib/jekyll/utils.rb new file mode 100644 index 00000000..d74174c4 --- /dev/null +++ b/lib/jekyll/utils.rb @@ -0,0 +1,79 @@ +module Jekyll + module Utils + class << self + + # Merges a master hash with another hash, recursively. + # + # master_hash - the "parent" hash whose values will be overridden + # other_hash - the other hash whose values will be persisted after the merge + # + # This code was lovingly stolen from some random gem: + # http://gemjack.com/gems/tartan-0.1.1/classes/Hash.html + # + # Thanks to whoever made it. + def deep_merge_hashes(master_hash, other_hash) + target = master_hash.dup + + other_hash.keys.each do |key| + if other_hash[key].is_a? Hash and target[key].is_a? Hash + target[key] = Utils.deep_merge_hashes(target[key], other_hash[key]) + next + end + + target[key] = other_hash[key] + end + + target + end + + # Read array from the supplied hash favouring the singular key + # and then the plural key, and handling any nil entries. + # + # hash - the hash to read from + # singular_key - the singular key + # plural_key - the plural key + # + # Returns an array + def pluralized_array_from_hash(hash, singular_key, plural_key) + if hash.has_key?(singular_key) + array = [hash[singular_key]] if hash[singular_key] + elsif hash.has_key?(plural_key) + case hash[plural_key] + when String + array = hash[plural_key].split + when Array + array = hash[plural_key].compact + end + end + array || [] + end + + # Apply #to_sym to all keys in the hash + # + # hash - the hash to which to apply this transformation + # + # Returns a new hash with symbolized keys + def symbolize_hash_keys(hash) + target = hash.dup + target.keys.each do |key| + target[(key.to_sym rescue key) || key] = target.delete(key) + end + target + end + + # Apply #to_s to all keys in the Hash + # + # hash - the hash to which to apply this transformation + # + # Returns a new hash with stringified keys + def stringify_hash_keys(hash) + target = hash.dup + target.keys.each do |key| + target[(key.to_s rescue key) || key] = target.delete(key) + end + target + end + + end + end +end diff --git a/test/helper.rb b/test/helper.rb index 97faab12..b9b7e4cd 100644 --- a/test/helper.rb +++ b/test/helper.rb @@ -28,6 +28,17 @@ STDERR.reopen(test(?e, '/dev/null') ? '/dev/null' : 'NUL:') class Test::Unit::TestCase include RR::Adapters::TestUnit + def build_configs(overrides, base_hash = Jekyll::Configuration::DEFAULTS) + Utils.deep_merge_hashes(base_hash, overrides) + end + + def site_configuration(overrides = {}) + build_configs({ + "source" => source_dir, + "destination" => dest_dir + }, build_configs(overrides)) + end + def dest_dir(*subdirs) test_dir('dest', *subdirs) end diff --git a/test/test_configuration.rb b/test/test_configuration.rb index a390da81..3a8918f9 100644 --- a/test/test_configuration.rb +++ b/test/test_configuration.rb @@ -156,7 +156,7 @@ class TestConfiguration < Test::Unit::TestCase should "load different config if specified" do mock(SafeYAML).load_file(@paths[:other]) { {"baseurl" => "http://wahoo.dev"} } mock($stdout).puts("Configuration file: #{@paths[:other]}") - assert_equal Jekyll::Configuration::DEFAULTS.deep_merge({ "baseurl" => "http://wahoo.dev" }), Jekyll.configuration({ "config" => @paths[:other] }) + assert_equal Utils.deep_merge_hashes(Jekyll::Configuration::DEFAULTS, { "baseurl" => "http://wahoo.dev" }), Jekyll.configuration({ "config" => @paths[:other] }) end should "load default config if path passed is empty" do @@ -186,7 +186,7 @@ class TestConfiguration < Test::Unit::TestCase mock(SafeYAML).load_file(@paths[:other]) { {"baseurl" => "http://wahoo.dev"} } mock($stdout).puts("Configuration file: #{@paths[:default]}") mock($stdout).puts("Configuration file: #{@paths[:other]}") - assert_equal Jekyll::Configuration::DEFAULTS.deep_merge({ "baseurl" => "http://wahoo.dev" }), Jekyll.configuration({ "config" => [@paths[:default], @paths[:other]] }) + assert_equal Utils.deep_merge_hashes(Jekyll::Configuration::DEFAULTS, { "baseurl" => "http://wahoo.dev" }), Jekyll.configuration({ "config" => [@paths[:default], @paths[:other]] }) end end end diff --git a/test/test_kramdown.rb b/test/test_kramdown.rb index 1d4c09ff..4bfe725e 100644 --- a/test/test_kramdown.rb +++ b/test/test_kramdown.rb @@ -35,7 +35,7 @@ class TestKramdown < Test::Unit::TestCase assert_match /
(“|“)Pit(’|’)hy(”|”)<\/p>/, @markdown.convert(%{"Pit'hy"}).strip override = { 'kramdown' => { 'smart_quotes' => 'lsaquo,rsaquo,laquo,raquo' } } - markdown = Converters::Markdown.new(@config.deep_merge(override)) + markdown = Converters::Markdown.new(Utils.deep_merge_hashes(@config, override)) assert_match /
(«|«)Pit(›|›)hy(»|»)<\/p>/, markdown.convert(%{"Pit'hy"}).strip end diff --git a/test/test_pager.rb b/test/test_pager.rb index b066b9a3..976925f0 100644 --- a/test/test_pager.rb +++ b/test/test_pager.rb @@ -3,12 +3,14 @@ require 'helper' class TestPager < Test::Unit::TestCase def build_site(config = {}) - base = Jekyll::Configuration::DEFAULTS.deep_merge({ + base = build_configs({ 'source' => source_dir, 'destination' => dest_dir, 'paginate' => 1 }) - site = Jekyll::Site.new(base.deep_merge(config)) + site = Jekyll::Site.new(site_configuration( + {"paginate" => 1}.merge(config) + )) site.process site end diff --git a/test/test_sass.rb b/test/test_sass.rb index 3e70e314..b39c8eea 100644 --- a/test/test_sass.rb +++ b/test/test_sass.rb @@ -1,13 +1,6 @@ require 'helper' class TestSass < Test::Unit::TestCase - def site_configuration(overrides = {}) - Jekyll::Configuration::DEFAULTS.deep_merge(overrides).deep_merge({ - "source" => source_dir, - "destination" => dest_dir - }) - end - def converter(overrides = {}) Jekyll::Converters::Sass.new(site_configuration({"sass" => overrides})) end diff --git a/test/test_tags.rb b/test/test_tags.rb index d7c8df24..a0a5c579 100644 --- a/test/test_tags.rb +++ b/test/test_tags.rb @@ -6,7 +6,9 @@ class TestTags < Test::Unit::TestCase def create_post(content, override = {}, converter_class = Jekyll::Converters::Markdown) stub(Jekyll).configuration do - Jekyll::Configuration::DEFAULTS.deep_merge({'highlighter' => 'pygments'}).deep_merge(override) + site_configuration({ + "highlighter" => "pygments" + }.merge(override)) end site = Site.new(Jekyll.configuration) @@ -545,7 +547,7 @@ CONTENT context "include tag with variable and liquid filters" do setup do stub(Jekyll).configuration do - Jekyll::Configuration::DEFAULTS.deep_merge({'pygments' => true}).deep_merge({'source' => source_dir, 'destination' => dest_dir}) + site_configuration({'pygments' => true}) end site = Site.new(Jekyll.configuration) diff --git a/test/test_core_ext.rb b/test/test_utils.rb similarity index 63% rename from test/test_core_ext.rb rename to test/test_utils.rb index c3e62cb5..cfd6c4a6 100644 --- a/test/test_core_ext.rb +++ b/test/test_utils.rb @@ -1,63 +1,63 @@ require 'helper' -class TestCoreExt < Test::Unit::TestCase +class TestUtils < Test::Unit::TestCase context "hash" do context "pluralized_array" do should "return empty array with no values" do data = {} - assert_equal [], data.pluralized_array('tag', 'tags') + assert_equal [], Utils.pluralized_array_from_hash(data, 'tag', 'tags') end should "return empty array with no matching values" do data = { 'foo' => 'bar' } - assert_equal [], data.pluralized_array('tag', 'tags') + assert_equal [], Utils.pluralized_array_from_hash(data, 'tag', 'tags') end should "return empty array with matching nil singular" do data = { 'foo' => 'bar', 'tag' => nil, 'tags' => ['dog', 'cat'] } - assert_equal [], data.pluralized_array('tag', 'tags') + assert_equal [], Utils.pluralized_array_from_hash(data, 'tag', 'tags') end should "return single value array with matching singular" do data = { 'foo' => 'bar', 'tag' => 'dog', 'tags' => ['dog', 'cat'] } - assert_equal ['dog'], data.pluralized_array('tag', 'tags') + assert_equal ['dog'], Utils.pluralized_array_from_hash(data, 'tag', 'tags') end should "return single value array with matching singular with spaces" do data = { 'foo' => 'bar', 'tag' => 'dog cat', 'tags' => ['dog', 'cat'] } - assert_equal ['dog cat'], data.pluralized_array('tag', 'tags') + assert_equal ['dog cat'], Utils.pluralized_array_from_hash(data, 'tag', 'tags') end should "return empty array with matching nil plural" do data = { 'foo' => 'bar', 'tags' => nil } - assert_equal [], data.pluralized_array('tag', 'tags') + assert_equal [], Utils.pluralized_array_from_hash(data, 'tag', 'tags') end should "return empty array with matching empty array" do data = { 'foo' => 'bar', 'tags' => [] } - assert_equal [], data.pluralized_array('tag', 'tags') + assert_equal [], Utils.pluralized_array_from_hash(data, 'tag', 'tags') end should "return single value array with matching plural with single string value" do data = { 'foo' => 'bar', 'tags' => 'dog' } - assert_equal ['dog'], data.pluralized_array('tag', 'tags') + assert_equal ['dog'], Utils.pluralized_array_from_hash(data, 'tag', 'tags') end should "return multiple value array with matching plural with single string value with spaces" do data = { 'foo' => 'bar', 'tags' => 'dog cat' } - assert_equal ['dog', 'cat'], data.pluralized_array('tag', 'tags') + assert_equal ['dog', 'cat'], Utils.pluralized_array_from_hash(data, 'tag', 'tags') end should "return single value array with matching plural with single value array" do data = { 'foo' => 'bar', 'tags' => ['dog'] } - assert_equal ['dog'], data.pluralized_array('tag', 'tags') + assert_equal ['dog'], Utils.pluralized_array_from_hash(data, 'tag', 'tags') end should "return multiple value array with matching plural with multiple value array" do data = { 'foo' => 'bar', 'tags' => ['dog', 'cat'] } - assert_equal ['dog', 'cat'], data.pluralized_array('tag', 'tags') + assert_equal ['dog', 'cat'], Utils.pluralized_array_from_hash(data, 'tag', 'tags') end end