{"action":"created","comment":{"url":"https://api.github.com/repos/rails/rails/pulls/comments/60489860","id":60489860,"diff_hunk":"@@ -112,12 +112,9 @@ class String\n   #\n   # @return [true, false]\n   def blank?\n-    # In practice, the majority of blank strings are empty. As of this writing\n-    # checking for empty? is about 3.5x faster than matching against the regexp\n-    # in MRI, so we call the predicate first, and then fallback.\n-    #\n-    # The penalty for blank strings with whitespace or present ones is marginal.\n-    empty? || BLANK_RE === self\n+    # Regex check is slow, only check non-empty strings.\n+    # A string not blank if it contains a single non-space string.\n+    empty? || !(/[[:^space:]]/ === self)","path":"activesupport/lib/active_support/core_ext/object/blank.rb","position":12,"original_position":12,"commit_id":"54243fecfc8867c79aa4adbfd9948ecd8dcbd8fc","original_commit_id":"54243fecfc8867c79aa4adbfd9948ecd8dcbd8fc","user":{"login":"tenderlove","id":3124,"avatar_url":"https://avatars.githubusercontent.com/u/3124?v=3","gravatar_id":"","url":"https://api.github.com/users/tenderlove","html_url":"https://github.com/tenderlove","followers_url":"https://api.github.com/users/tenderlove/followers","following_url":"https://api.github.com/users/tenderlove/following{/other_user}","gists_url":"https://api.github.com/users/tenderlove/gists{/gist_id}","starred_url":"https://api.github.com/users/tenderlove/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/tenderlove/subscriptions","organizations_url":"https://api.github.com/users/tenderlove/orgs","repos_url":"https://api.github.com/users/tenderlove/repos","events_url":"https://api.github.com/users/tenderlove/events{/privacy}","received_events_url":"https://api.github.com/users/tenderlove/received_events","type":"User","site_admin":true},"body":"Can you do `!~` and remove the `!`? Should be fewer instructions.","created_at":"2016-04-20T21:20:00Z","updated_at":"2016-04-20T21:20:00Z","html_url":"https://github.com/rails/rails/pull/24658#discussion_r60489860","pull_request_url":"https://api.github.com/repos/rails/rails/pulls/24658","_links":{"self":{"href":"https://api.github.com/repos/rails/rails/pulls/comments/60489860"},"html":{"href":"https://github.com/rails/rails/pull/24658#discussion_r60489860"},"pull_request":{"href":"https://api.github.com/repos/rails/rails/pulls/24658"}}},"pull_request":{"url":"https://api.github.com/repos/rails/rails/pulls/24658","id":67254644,"html_url":"https://github.com/rails/rails/pull/24658","diff_url":"https://github.com/rails/rails/pull/24658.diff","patch_url":"https://github.com/rails/rails/pull/24658.patch","issue_url":"https://api.github.com/repos/rails/rails/issues/24658","number":24658,"state":"open","locked":false,"title":"Speed up String#blank? Regex","user":{"login":"schneems","id":59744,"avatar_url":"https://avatars.githubusercontent.com/u/59744?v=3","gravatar_id":"","url":"https://api.github.com/users/schneems","html_url":"https://github.com/schneems","followers_url":"https://api.github.com/users/schneems/followers","following_url":"https://api.github.com/users/schneems/following{/other_user}","gists_url":"https://api.github.com/users/schneems/gists{/gist_id}","starred_url":"https://api.github.com/users/schneems/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/schneems/subscriptions","organizations_url":"https://api.github.com/users/schneems/orgs","repos_url":"https://api.github.com/users/schneems/repos","events_url":"https://api.github.com/users/schneems/events{/privacy}","received_events_url":"https://api.github.com/users/schneems/received_events","type":"User","site_admin":false},"body":"Follow up on https://github.com/rails/rails/commit/697384df36a939e565b7c08725017d49dc83fe40#commitcomment-17184696.\r\n\r\nThe regex to detect a blank string `/\\A[[:space:]]*\\z/` will loop through every character in the string to ensure that all of them are a `:space:` type. We can invert this logic and instead look for any non-`:space:` characters. When that happens, we would return on the first character found and the regex engine does not need to keep looking.\r\n\r\nThanks @nellshamrell for the regex talk at LSRC.\r\n\r\nBy defining a \"blank\" string as any string that does not have a non-whitespace character (yes, double negative) we can get a substantial speed bump.\r\n\r\nAlso an inline regex is (barely) faster than a regex in a constant, since it skips the constant lookup. A regex literal is frozen by default.\r\n\r\n```ruby\r\nrequire 'benchmark/ips'\r\n\r\ndef string_generate\r\n  str = \" abcdefghijklmnopqrstuvwxyz\\t\".freeze\r\n  str[rand(0..(str.length - 1))] * rand(0..23)\r\nend\r\n\r\nstrings = 100.times.map { string_generate }\r\n\r\nALL_WHITESPACE_STAR = /\\A[[:space:]]*\\z/\r\n\r\nBenchmark.ips do |x|\r\n  x.report('current regex            ') { strings.each {|str| str.empty? || ALL_WHITESPACE_STAR === str } }\r\n  x.report('not a non-whitespace char') { strings.each {|str| str.empty? || !(/[[:^space:]]/ === str) } }\r\n  x.compare!\r\nend\r\n\r\n# Warming up --------------------------------------\r\n# current regex\r\n#                          1.744k i/100ms\r\n# not a non-whitespace char\r\n#                          2.264k i/100ms\r\n# Calculating -------------------------------------\r\n# current regex\r\n#                          18.078k (± 8.9%) i/s -     90.688k\r\n# not a non-whitespace char\r\n#                          23.580k (± 7.1%) i/s -    117.728k\r\n\r\n# Comparison:\r\n# not a non-whitespace char:    23580.3 i/s\r\n# current regex            :    18078.2 i/s - 1.30x slower\r\n```\r\n\r\nThis makes the method roughly 30% faster `(23.580 - 18.078)/18.078 * 100`.\r\n\r\ncc/ @fxn","created_at":"2016-04-20T20:40:57Z","updated_at":"2016-04-20T21:20:00Z","closed_at":null,"merged_at":null,"merge_commit_sha":"fc5dd871af4c5f27f50f9add969224bf561beacd","assignee":null,"milestone":null,"commits_url":"https://api.github.com/repos/rails/rails/pulls/24658/commits","review_comments_url":"https://api.github.com/repos/rails/rails/pulls/24658/comments","review_comment_url":"https://api.github.com/repos/rails/rails/pulls/comments{/number}","comments_url":"https://api.github.com/repos/rails/rails/issues/24658/comments","statuses_url":"https://api.github.com/repos/rails/rails/statuses/54243fecfc8867c79aa4adbfd9948ecd8dcbd8fc","head":{"label":"schneems:schneems/faster-regex-blank-string","ref":"schneems/faster-regex-blank-string","sha":"54243fecfc8867c79aa4adbfd9948ecd8dcbd8fc","user":{"login":"schneems","id":59744,"avatar_url":"https://avatars.githubusercontent.com/u/59744?v=3","gravatar_id":"","url":"https://api.github.com/users/schneems","html_url":"https://github.com/schneems","followers_url":"https://api.github.com/users/schneems/followers","following_url":"https://api.github.com/users/schneems/following{/other_user}","gists_url":"https://api.github.com/users/schneems/gists{/gist_id}","starred_url":"https://api.github.com/users/schneems/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/schneems/subscriptions","organizations_url":"https://api.github.com/users/schneems/orgs","repos_url":"https://api.github.com/users/schneems/repos","events_url":"https://api.github.com/users/schneems/events{/privacy}","received_events_url":"https://api.github.com/users/schneems/received_events","type":"User","site_admin":false},"repo":{"id":2873136,"name":"rails","full_name":"schneems/rails","owner":{"login":"schneems","id":59744,"avatar_url":"https://avatars.githubusercontent.com/u/59744?v=3","gravatar_id":"","url":"https://api.github.com/users/schneems","html_url":"https://github.com/schneems","followers_url":"https://api.github.com/users/schneems/followers","following_url":"https://api.github.com/users/schneems/following{/other_user}","gists_url":"https://api.github.com/users/schneems/gists{/gist_id}","starred_url":"https://api.github.com/users/schneems/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/schneems/subscriptions","organizations_url":"https://api.github.com/users/schneems/orgs","repos_url":"https://api.github.com/users/schneems/repos","events_url":"https://api.github.com/users/schneems/events{/privacy}","received_events_url":"https://api.github.com/users/schneems/received_events","type":"User","site_admin":false},"private":false,"html_url":"https://github.com/schneems/rails","description":"Ruby on Rails","fork":true,"url":"https://api.github.com/repos/schneems/rails","forks_url":"https://api.github.com/repos/schneems/rails/forks","keys_url":"https://api.github.com/repos/schneems/rails/keys{/key_id}","collaborators_url":"https://api.github.com/repos/schneems/rails/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/schneems/rails/teams","hooks_url":"https://api.github.com/repos/schneems/rails/hooks","issue_events_url":"https://api.github.com/repos/schneems/rails/issues/events{/number}","events_url":"https://api.github.com/repos/schneems/rails/events","assignees_url":"https://api.github.com/repos/schneems/rails/assignees{/user}","branches_url":"https://api.github.com/repos/schneems/rails/branches{/branch}","tags_url":"https://api.github.com/repos/schneems/rails/tags","blobs_url":"https://api.github.com/repos/schneems/rails/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/schneems/rails/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/schneems/rails/git/refs{/sha}","trees_url":"https://api.github.com/repos/schneems/rails/git/trees{/sha}","statuses_url":"https://api.github.com/repos/schneems/rails/statuses/{sha}","languages_url":"https://api.github.com/repos/schneems/rails/languages","stargazers_url":"https://api.github.com/repos/schneems/rails/stargazers","contributors_url":"https://api.github.com/repos/schneems/rails/contributors","subscribers_url":"https://api.github.com/repos/schneems/rails/subscribers","subscription_url":"https://api.github.com/repos/schneems/rails/subscription","commits_url":"https://api.github.com/repos/schneems/rails/commits{/sha}","git_commits_url":"https://api.github.com/repos/schneems/rails/git/commits{/sha}","comments_url":"https://api.github.com/repos/schneems/rails/comments{/number}","issue_comment_url":"https://api.github.com/repos/schneems/rails/issues/comments{/number}","contents_url":"https://api.github.com/repos/schneems/rails/contents/{+path}","compare_url":"https://api.github.com/repos/schneems/rails/compare/{base}...{head}","merges_url":"https://api.github.com/repos/schneems/rails/merges","archive_url":"https://api.github.com/repos/schneems/rails/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/schneems/rails/downloads","issues_url":"https://api.github.com/repos/schneems/rails/issues{/number}","pulls_url":"https://api.github.com/repos/schneems/rails/pulls{/number}","milestones_url":"https://api.github.com/repos/schneems/rails/milestones{/number}","notifications_url":"https://api.github.com/repos/schneems/rails/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/schneems/rails/labels{/name}","releases_url":"https://api.github.com/repos/schneems/rails/releases{/id}","deployments_url":"https://api.github.com/repos/schneems/rails/deployments","created_at":"2011-11-29T06:48:49Z","updated_at":"2015-01-08T18:17:54Z","pushed_at":"2016-04-20T20:40:13Z","git_url":"git://github.com/schneems/rails.git","ssh_url":"git@github.com:schneems/rails.git","clone_url":"https://github.com/schneems/rails.git","svn_url":"https://github.com/schneems/rails","homepage":"http://rubyonrails.org","size":118736,"stargazers_count":2,"watchers_count":2,"language":"Ruby","has_issues":false,"has_downloads":true,"has_wiki":false,"has_pages":false,"forks_count":0,"mirror_url":null,"open_issues_count":0,"forks":0,"open_issues":0,"watchers":2,"default_branch":"master"}},"base":{"label":"rails:master","ref":"master","sha":"3ff6b800f2fc3552d98a0a31947c66a21e4479eb","user":{"login":"rails","id":4223,"avatar_url":"https://avatars.githubusercontent.com/u/4223?v=3","gravatar_id":"","url":"https://api.github.com/users/rails","html_url":"https://github.com/rails","followers_url":"https://api.github.com/users/rails/followers","following_url":"https://api.github.com/users/rails/following{/other_user}","gists_url":"https://api.github.com/users/rails/gists{/gist_id}","starred_url":"https://api.github.com/users/rails/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/rails/subscriptions","organizations_url":"https://api.github.com/users/rails/orgs","repos_url":"https://api.github.com/users/rails/repos","events_url":"https://api.github.com/users/rails/events{/privacy}","received_events_url":"https://api.github.com/users/rails/received_events","type":"Organization","site_admin":false},"repo":{"id":8514,"name":"rails","full_name":"rails/rails","owner":{"login":"rails","id":4223,"avatar_url":"https://avatars.githubusercontent.com/u/4223?v=3","gravatar_id":"","url":"https://api.github.com/users/rails","html_url":"https://github.com/rails","followers_url":"https://api.github.com/users/rails/followers","following_url":"https://api.github.com/users/rails/following{/other_user}","gists_url":"https://api.github.com/users/rails/gists{/gist_id}","starred_url":"https://api.github.com/users/rails/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/rails/subscriptions","organizations_url":"https://api.github.com/users/rails/orgs","repos_url":"https://api.github.com/users/rails/repos","events_url":"https://api.github.com/users/rails/events{/privacy}","received_events_url":"https://api.github.com/users/rails/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/rails/rails","description":"Ruby on Rails","fork":false,"url":"https://api.github.com/repos/rails/rails","forks_url":"https://api.github.com/repos/rails/rails/forks","keys_url":"https://api.github.com/repos/rails/rails/keys{/key_id}","collaborators_url":"https://api.github.com/repos/rails/rails/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/rails/rails/teams","hooks_url":"https://api.github.com/repos/rails/rails/hooks","issue_events_url":"https://api.github.com/repos/rails/rails/issues/events{/number}","events_url":"https://api.github.com/repos/rails/rails/events","assignees_url":"https://api.github.com/repos/rails/rails/assignees{/user}","branches_url":"https://api.github.com/repos/rails/rails/branches{/branch}","tags_url":"https://api.github.com/repos/rails/rails/tags","blobs_url":"https://api.github.com/repos/rails/rails/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/rails/rails/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/rails/rails/git/refs{/sha}","trees_url":"https://api.github.com/repos/rails/rails/git/trees{/sha}","statuses_url":"https://api.github.com/repos/rails/rails/statuses/{sha}","languages_url":"https://api.github.com/repos/rails/rails/languages","stargazers_url":"https://api.github.com/repos/rails/rails/stargazers","contributors_url":"https://api.github.com/repos/rails/rails/contributors","subscribers_url":"https://api.github.com/repos/rails/rails/subscribers","subscription_url":"https://api.github.com/repos/rails/rails/subscription","commits_url":"https://api.github.com/repos/rails/rails/commits{/sha}","git_commits_url":"https://api.github.com/repos/rails/rails/git/commits{/sha}","comments_url":"https://api.github.com/repos/rails/rails/comments{/number}","issue_comment_url":"https://api.github.com/repos/rails/rails/issues/comments{/number}","contents_url":"https://api.github.com/repos/rails/rails/contents/{+path}","compare_url":"https://api.github.com/repos/rails/rails/compare/{base}...{head}","merges_url":"https://api.github.com/repos/rails/rails/merges","archive_url":"https://api.github.com/repos/rails/rails/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/rails/rails/downloads","issues_url":"https://api.github.com/repos/rails/rails/issues{/number}","pulls_url":"https://api.github.com/repos/rails/rails/pulls{/number}","milestones_url":"https://api.github.com/repos/rails/rails/milestones{/number}","notifications_url":"https://api.github.com/repos/rails/rails/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/rails/rails/labels{/name}","releases_url":"https://api.github.com/repos/rails/rails/releases{/id}","deployments_url":"https://api.github.com/repos/rails/rails/deployments","created_at":"2008-04-11T02:19:47Z","updated_at":"2016-04-20T21:01:28Z","pushed_at":"2016-04-20T20:48:48Z","git_url":"git://github.com/rails/rails.git","ssh_url":"git@github.com:rails/rails.git","clone_url":"https://github.com/rails/rails.git","svn_url":"https://github.com/rails/rails","homepage":"http://rubyonrails.org","size":331987,"stargazers_count":30720,"watchers_count":30720,"language":"Ruby","has_issues":true,"has_downloads":true,"has_wiki":false,"has_pages":false,"forks_count":12476,"mirror_url":null,"open_issues_count":925,"forks":12476,"open_issues":925,"watchers":30720,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/rails/rails/pulls/24658"},"html":{"href":"https://github.com/rails/rails/pull/24658"},"issue":{"href":"https://api.github.com/repos/rails/rails/issues/24658"},"comments":{"href":"https://api.github.com/repos/rails/rails/issues/24658/comments"},"review_comments":{"href":"https://api.github.com/repos/rails/rails/pulls/24658/comments"},"review_comment":{"href":"https://api.github.com/repos/rails/rails/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/rails/rails/pulls/24658/commits"},"statuses":{"href":"https://api.github.com/repos/rails/rails/statuses/54243fecfc8867c79aa4adbfd9948ecd8dcbd8fc"}}}}