From 95e96a0f839c8f64840c4c31c3255862351ce927 Mon Sep 17 00:00:00 2001 From: Parker Moore Date: Wed, 22 Oct 2014 00:56:54 -0700 Subject: [PATCH 01/14] Add a benchmarking script for string-concat --- benchmark/string-concat | 8 ++++++++ 1 file changed, 8 insertions(+) create mode 100644 benchmark/string-concat diff --git a/benchmark/string-concat b/benchmark/string-concat new file mode 100644 index 00000000..c4a91748 --- /dev/null +++ b/benchmark/string-concat @@ -0,0 +1,8 @@ +require 'benchmark/ips' + +url = "http://jekyllrb.com" + +Benchmark.ips do |x| + x.report('+=') { url += '/' } + x.report('<<') { url << '/' } +end From b9c4fc93d7c3eabeaefb9d5fe1ec15453126a164 Mon Sep 17 00:00:00 2001 From: Parker Moore Date: Wed, 22 Oct 2014 00:57:06 -0700 Subject: [PATCH 02/14] Use flat_map instead of map.flatten --- lib/jekyll/cleaner.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/jekyll/cleaner.rb b/lib/jekyll/cleaner.rb index 0aa3cdfd..c578c9b8 100644 --- a/lib/jekyll/cleaner.rb +++ b/lib/jekyll/cleaner.rb @@ -49,7 +49,7 @@ module Jekyll # # Returns a Set with the directory paths def new_dirs - new_files.map { |file| parent_dirs(file) }.flatten.to_set + new_files.flat_map { |file| parent_dirs(file) }.to_set end # Private: The list of parent directories of a given file @@ -76,7 +76,7 @@ module Jekyll # # Returns a Set with the directory paths def keep_dirs - site.keep_files.map{|file| parent_dirs(File.join(site.dest, file))}.flatten.to_set + site.keep_files.flat_map { |file| parent_dirs(File.join(site.dest, file)) }.to_set end # Private: Creates a regular expression from the config's keep_files array From 3227c4ecea422ee48a87ece6bf5c950ec5ab9f0f Mon Sep 17 00:00:00 2001 From: Parker Moore Date: Wed, 22 Oct 2014 00:57:25 -0700 Subject: [PATCH 03/14] Use #tr instead of #gsub --- lib/jekyll/url.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/jekyll/url.rb b/lib/jekyll/url.rb index f4ea4d33..310d9e43 100644 --- a/lib/jekyll/url.rb +++ b/lib/jekyll/url.rb @@ -46,7 +46,7 @@ module Jekyll # Returns the _unsanitizied_ String URL def generate_url @placeholders.inject(@template) do |result, token| - result.gsub(/:#{token.first}/, self.class.escape_path(token.last)) + result.tr(":#{token.first}", self.class.escape_path(token.last)) end end From 1395d5686be12d90ebde42b1857b3d0d4b104340 Mon Sep 17 00:00:00 2001 From: Parker Moore Date: Wed, 22 Oct 2014 00:57:53 -0700 Subject: [PATCH 04/14] Optimize more URL#sanitize_url --- lib/jekyll/url.rb | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/lib/jekyll/url.rb b/lib/jekyll/url.rb index 310d9e43..964c619d 100644 --- a/lib/jekyll/url.rb +++ b/lib/jekyll/url.rb @@ -52,19 +52,19 @@ module Jekyll # Returns a sanitized String URL def sanitize_url(in_url) + url = in_url + # Remove all double slashes + .tr('//', '/') \ - # Remove all double slashes - url = in_url.gsub(/\/\//, "/") + # Remove every URL segment that consists solely of dots + .split('/').reject{ |part| part =~ /^\.+$/ }.join('/') \ - # Remove every URL segment that consists solely of dots - url = url.split('/').reject{ |part| part =~ /^\.+$/ }.join('/') + # Always add a leading slash + .gsub(/\A([^\/])/, '/\1') # Append a trailing slash to the URL if the unsanitized URL had one url += "/" if in_url =~ /\/$/ - # Always add a leading slash - url.gsub!(/\A([^\/])/, '/\1') - url end From 0511ece2f5b737ec0de96d01b8817ae570ff2518 Mon Sep 17 00:00:00 2001 From: Parker Moore Date: Wed, 22 Oct 2014 00:58:20 -0700 Subject: [PATCH 05/14] Use String#<< instead of String#+= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit I just couldn’t believe this but look: ~/jekyll/jekyll#master$ ruby benchmark/string-concat Calculating ------------------------------------- += 6367 i/100ms << 128697 i/100ms ------------------------------------------------- += 1704.3 (±0.6%) i/s - 12734 in 7.472170s << 4381212.4 (±6.3%) i/s - 21878490 in 5.014899s WOW. --- lib/jekyll/url.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/jekyll/url.rb b/lib/jekyll/url.rb index 964c619d..8773e018 100644 --- a/lib/jekyll/url.rb +++ b/lib/jekyll/url.rb @@ -63,7 +63,7 @@ module Jekyll .gsub(/\A([^\/])/, '/\1') # Append a trailing slash to the URL if the unsanitized URL had one - url += "/" if in_url =~ /\/$/ + url << "/" if in_url =~ /\/$/ url end From 4e07dfef1febe61e710d81a77e2bfd2623f6d594 Mon Sep 17 00:00:00 2001 From: Parker Moore Date: Wed, 22 Oct 2014 01:11:34 -0700 Subject: [PATCH 06/14] Add benchmark for hash-fetch MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Calculating ------------------------------------- fetch with no block 66979 i/100ms fetch with a block 138257 i/100ms brackets with an || 145792 i/100ms ------------------------------------------------- fetch with no block 1255521.2 (±5.2%) i/s - 6296026 in 5.028856s fetch with a block 6402972.5 (±8.1%) i/s - 31799110 in 5.002554s brackets with an || 8536511.4 (±8.1%) i/s - 42425472 in 5.005831s --- benchmark/hash-fetch | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100644 benchmark/hash-fetch diff --git a/benchmark/hash-fetch b/benchmark/hash-fetch new file mode 100644 index 00000000..35708357 --- /dev/null +++ b/benchmark/hash-fetch @@ -0,0 +1,9 @@ +require 'benchmark/ips' + +h = {:bar => 'uco'} + +Benchmark.ips do |x| + x.report('fetch with no block') { h.fetch(:bar, (0..9).to_a) } + x.report('fetch with a block') { h.fetch(:bar) { (0..9).to_a } } + x.report('brackets with an ||') { h[:bar] || (0..9).to_a } +end From 7e37892bbdf7192d9c4b9217f74fd9a8cf938299 Mon Sep 17 00:00:00 2001 From: Parker Moore Date: Wed, 22 Oct 2014 01:17:22 -0700 Subject: [PATCH 07/14] Add a benchmark for symbol-to-proc MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Calculating ------------------------------------- block 5403 i/100ms &:to_s 6094 i/100ms ------------------------------------------------- block 60023.4 (±5.3%) i/s - 302568 in 5.055537s &:to_s 59047.0 (±4.9%) i/s - 298606 in 5.068991s --- benchmark/symbol-to-proc | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 benchmark/symbol-to-proc diff --git a/benchmark/symbol-to-proc b/benchmark/symbol-to-proc new file mode 100644 index 00000000..bc08b2f2 --- /dev/null +++ b/benchmark/symbol-to-proc @@ -0,0 +1,6 @@ +require 'benchmark/ips' + +Benchmark.ips do |x| + x.report('block') { (1..100).map { |i| i.to_s } } + x.report('&:to_s') { (1..100).map(&:to_s) } +end From 7c05312d5c9676837730ad7db834e14202bbd72d Mon Sep 17 00:00:00 2001 From: Parker Moore Date: Wed, 22 Oct 2014 01:18:09 -0700 Subject: [PATCH 08/14] Add benchmark for yield vs proc.call MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Calculating ------------------------------------- yield 70018 i/100ms block.call 42809 i/100ms ------------------------------------------------- yield 1099624.2 (±7.3%) i/s - 5531422 in 5.056107s block.call 604006.1 (±7.1%) i/s - 3039439 in 5.058794s --- benchmark/proc-call-vs-yield | 14 ++++++++++++++ 1 file changed, 14 insertions(+) create mode 100644 benchmark/proc-call-vs-yield diff --git a/benchmark/proc-call-vs-yield b/benchmark/proc-call-vs-yield new file mode 100644 index 00000000..3d55979b --- /dev/null +++ b/benchmark/proc-call-vs-yield @@ -0,0 +1,14 @@ +require 'benchmark/ips' + +def fast + yield +end + +def slow(&block) + block.call +end + +Benchmark.ips do |x| + x.report('yield') { fast { (0..9).to_a } } + x.report('block.call') { slow { (0..9).to_a } } +end From a30498ba42a3b265e31889d80f0fbd22ee2eff3b Mon Sep 17 00:00:00 2001 From: Parker Moore Date: Wed, 22 Oct 2014 01:27:45 -0700 Subject: [PATCH 09/14] Add benchmark for #flat_map MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Calculating ------------------------------------- .map.flatten with nested arrays 4718 i/100ms .flat_map with nested arrays 6048 i/100ms .map.flatten with no nested arrays 9804 i/100ms .flat_map with no nested arrays 9302 i/100ms ------------------------------------------------- .map.flatten with nested arrays 48118.3 (±4.8%) i/s - 240618 in 5.011942s .flat_map with nested arrays 63838.6 (±5.1%) i/s - 320544 in 5.034864s .map.flatten with no nested arrays 104879.3 (±4.4%) i/s - 529416 in 5.057802s .flat_map with no nested arrays 99935.3 (±6.6%) i/s - 502308 in 5.049506s --- benchmark/flat-map | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) create mode 100644 benchmark/flat-map diff --git a/benchmark/flat-map b/benchmark/flat-map new file mode 100644 index 00000000..b10c5c9a --- /dev/null +++ b/benchmark/flat-map @@ -0,0 +1,17 @@ +require 'benchmark/ips' + +enum = (0..50).to_a +nested = enum.map { |i| [i] } + +def do_thing(blah) + blah * 1 +end + +Benchmark.ips do |x| + x.report('.map.flatten with nested arrays') { nested.map { |i| do_thing(i) }.flatten(1) } + x.report('.flat_map with nested arrays') { nested.flat_map { |i| do_thing(i) } } + + x.report('.map.flatten with no nested arrays') { enum.map { |i| do_thing(i) }.flatten(1) } + x.report('.flat_map with no nested arrays') { enum.flat_map { |i| do_thing(i) } } +end + From e028d50b3fcd075c5912575eba91c62b47902c4c Mon Sep 17 00:00:00 2001 From: Parker Moore Date: Wed, 22 Oct 2014 01:36:43 -0700 Subject: [PATCH 10/14] Add benchmark around string replacement. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Calculating ------------------------------------- #tr 62416 i/100ms #gsub 33750 i/100ms #gsub! 29695 i/100ms #sub 60774 i/100ms #sub! 64955 i/100ms ------------------------------------------------- #tr 989348.8 (±5.0%) i/s - 4993280 in 5.060836s #gsub 422892.9 (±4.3%) i/s - 2126250 in 5.037741s #gsub! 364115.6 (±4.0%) i/s - 1841090 in 5.064496s #sub 964336.6 (±4.4%) i/s - 4861920 in 5.051775s #sub! 1016598.5 (±4.7%) i/s - 5131445 in 5.058987s --- benchmark/string-replacement | 13 +++++++++++++ 1 file changed, 13 insertions(+) create mode 100644 benchmark/string-replacement diff --git a/benchmark/string-replacement b/benchmark/string-replacement new file mode 100644 index 00000000..13715376 --- /dev/null +++ b/benchmark/string-replacement @@ -0,0 +1,13 @@ +require 'benchmark/ips' + +def str + 'http://baruco.org/2014/some-talk-with-some-amount-of-value' +end + +Benchmark.ips do |x| + x.report('#tr') { str.tr('some', 'a') } + x.report('#gsub') { str.gsub('some', 'a') } + x.report('#gsub!') { str.gsub!('some', 'a') } + x.report('#sub') { str.sub('some', 'a') } + x.report('#sub!') { str.sub!('some', 'a') } +end From ab3f27e6740f736fa37f550846c2cffd4a490e39 Mon Sep 17 00:00:00 2001 From: Parker Moore Date: Wed, 22 Oct 2014 01:40:55 -0700 Subject: [PATCH 11/14] Add benchmark for sequential assignment. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Calculating ------------------------------------- parallel assignment 126425 i/100ms multi-line assignment 136492 i/100ms ------------------------------------------------- parallel assignment 6382145.2 (±10.1%) i/s - 31606250 in 5.006184s multi-line assignment 9281041.8 (±11.7%) i/s - 45724820 in 5.001599s --- benchmark/sequential-assignment | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 benchmark/sequential-assignment diff --git a/benchmark/sequential-assignment b/benchmark/sequential-assignment new file mode 100644 index 00000000..945e982b --- /dev/null +++ b/benchmark/sequential-assignment @@ -0,0 +1,11 @@ +require 'benchmark/ips' + +Benchmark.ips do |x| + x.report('parallel assignment') do + a, b = 1, 2 + end + x.report('multi-line assignment') do + a = 1 + b = 2 + end +end From 2eb318a929713836e533834323062a8cf50b9645 Mon Sep 17 00:00:00 2001 From: Parker Moore Date: Wed, 22 Oct 2014 01:43:46 -0700 Subject: [PATCH 12/14] Replace costly Hash#fetch with arity=2 with arity=1 + block. --- lib/jekyll/page.rb | 2 +- lib/jekyll/post.rb | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/jekyll/page.rb b/lib/jekyll/page.rb index d045b7c2..dcbd3ac5 100644 --- a/lib/jekyll/page.rb +++ b/lib/jekyll/page.rb @@ -126,7 +126,7 @@ module Jekyll # # Returns the path to the source file def path - data.fetch('path', relative_path.sub(/\A\//, '')) + data.fetch('path') { relative_path.sub(/\A\//, '') } end # The path to the page source file, relative to the site source diff --git a/lib/jekyll/post.rb b/lib/jekyll/post.rb index 293e2c5d..f816e165 100644 --- a/lib/jekyll/post.rb +++ b/lib/jekyll/post.rb @@ -108,14 +108,14 @@ module Jekyll # # Returns excerpt string. def excerpt - data.fetch('excerpt', extracted_excerpt.to_s) + data.fetch('excerpt') { extracted_excerpt.to_s } end # Public: the Post title, from the YAML Front-Matter or from the slug # # Returns the post title def title - data.fetch("title", titleized_slug) + data.fetch("title") { titleized_slug } end # Turns the post slug into a suitable title @@ -130,7 +130,7 @@ module Jekyll # # Returns the path to the file relative to the site source def path - data.fetch('path', relative_path.sub(/\A\//, '')) + data.fetch('path') { relative_path.sub(/\A\//, '') } end # The path to the post source file, relative to the site source From 5cb0aee251af302e243707bf1dbf70c517377087 Mon Sep 17 00:00:00 2001 From: Parker Moore Date: Wed, 22 Oct 2014 02:10:21 -0700 Subject: [PATCH 13/14] Have to go back on all these... --- lib/jekyll/cleaner.rb | 4 ++-- lib/jekyll/post.rb | 2 +- lib/jekyll/url.rb | 11 +++++------ 3 files changed, 8 insertions(+), 9 deletions(-) diff --git a/lib/jekyll/cleaner.rb b/lib/jekyll/cleaner.rb index c578c9b8..1786a317 100644 --- a/lib/jekyll/cleaner.rb +++ b/lib/jekyll/cleaner.rb @@ -49,7 +49,7 @@ module Jekyll # # Returns a Set with the directory paths def new_dirs - new_files.flat_map { |file| parent_dirs(file) }.to_set + new_files.map { |file| parent_dirs(file) }.flatten.to_set end # Private: The list of parent directories of a given file @@ -76,7 +76,7 @@ module Jekyll # # Returns a Set with the directory paths def keep_dirs - site.keep_files.flat_map { |file| parent_dirs(File.join(site.dest, file)) }.to_set + site.keep_files.map { |file| parent_dirs(File.join(site.dest, file)) }.flatten.to_set end # Private: Creates a regular expression from the config's keep_files array diff --git a/lib/jekyll/post.rb b/lib/jekyll/post.rb index f816e165..68b85acb 100644 --- a/lib/jekyll/post.rb +++ b/lib/jekyll/post.rb @@ -115,7 +115,7 @@ module Jekyll # # Returns the post title def title - data.fetch("title") { titleized_slug } + data.fetch('title') { titleized_slug } end # Turns the post slug into a suitable title diff --git a/lib/jekyll/url.rb b/lib/jekyll/url.rb index 8773e018..56173de6 100644 --- a/lib/jekyll/url.rb +++ b/lib/jekyll/url.rb @@ -46,24 +46,23 @@ module Jekyll # Returns the _unsanitizied_ String URL def generate_url @placeholders.inject(@template) do |result, token| - result.tr(":#{token.first}", self.class.escape_path(token.last)) + break result if result.index(':').nil? + result.gsub(':#{token.first}', self.class.escape_path(token.last)) end end # Returns a sanitized String URL def sanitize_url(in_url) - url = in_url + url = in_url \ # Remove all double slashes - .tr('//', '/') \ - + .gsub(/\/\//, '/') \ # Remove every URL segment that consists solely of dots .split('/').reject{ |part| part =~ /^\.+$/ }.join('/') \ - # Always add a leading slash .gsub(/\A([^\/])/, '/\1') # Append a trailing slash to the URL if the unsanitized URL had one - url << "/" if in_url =~ /\/$/ + url << "/" if in_url[-1].eql?('/') url end From ae01b1d5dfd0a86d81eb8807f3d4dcd30104634b Mon Sep 17 00:00:00 2001 From: Parker Moore Date: Wed, 22 Oct 2014 02:16:50 -0700 Subject: [PATCH 14/14] :frowning: --- lib/jekyll/url.rb | 2 +- test/test_url.rb | 7 +++++++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/lib/jekyll/url.rb b/lib/jekyll/url.rb index 56173de6..777ae3d1 100644 --- a/lib/jekyll/url.rb +++ b/lib/jekyll/url.rb @@ -47,7 +47,7 @@ module Jekyll def generate_url @placeholders.inject(@template) do |result, token| break result if result.index(':').nil? - result.gsub(':#{token.first}', self.class.escape_path(token.last)) + result.gsub(/:#{token.first}/, self.class.escape_path(token.last)) end end diff --git a/test/test_url.rb b/test/test_url.rb index 0576eda2..dcbe8bed 100644 --- a/test/test_url.rb +++ b/test/test_url.rb @@ -16,6 +16,13 @@ class TestURL < Test::Unit::TestCase ).to_s end + should "handle multiple of the same key in the template" do + assert_equal '/foo/bar/foo/', URL.new( + :template => "/:x/:y/:x/", + :placeholders => {:x => "foo", :y => "bar"} + ).to_s + end + should "return permalink if given" do assert_equal "/le/perma/link", URL.new( :template => "/:x/:y",