###

alias hbin me

Rails raw, html_safe vs html_escape(h) and benchmark

  • raw is a wrapper around String#html_safe.
  • String#html_safe just returns an instance of ActiveSupport::SafeBuffer.

@Daniel wrote a post about when to use raw() and when to use .html_safe

  • html_escape originally defined in ERB::Util.html_escape, also aliased as: h

There are several html escaption methods, here is the benchmark:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
require 'benchmark/ips'
require 'open-uri'

require 'cgi'
require 'erb'
require 'rack'

puts "===== Short String =====\n\n"

Benchmark.ips do |x|
  SHORT_STR = %(<html><head></head><body></body></html>)

  x.report 'CGI::escapeHTML' do
    CGI::escapeHTML SHORT_STR
  end

  x.report 'ERB::Util.html_escape' do
    ERB::Util.html_escape SHORT_STR
  end

  x.report 'Rack::Utils.escape_html' do
    Rack::Utils.escape_html SHORT_STR
  end

  x.compare!
end

puts "===== Long String =====\n\n"

Benchmark.ips do |x|
  LONG_STR  = open('http://example.com/').read

  x.report 'CGI::escapeHTML' do
    CGI::escapeHTML LONG_STR
  end

  x.report 'ERB::Util.html_escape' do
    ERB::Util.html_escape LONG_STR
  end

  x.report 'Rack::Utils.escape_html' do
    Rack::Utils.escape_html LONG_STR
  end

  x.compare!
end

require 'active_support/core_ext/string'

puts "===== Short html safe string =====\n\n"

Benchmark.ips do |x|
  SHORT_HTML_SAFE_STR = %(<html><head></head><body></body></html>).html_safe

  x.report 'CGI::escapeHTML' do
    CGI::escapeHTML SHORT_HTML_SAFE_STR
  end

  x.report 'ERB::Util.html_escape' do
    ERB::Util.html_escape SHORT_HTML_SAFE_STR
  end

  x.report 'Rack::Utils.escape_html' do
    Rack::Utils.escape_html SHORT_HTML_SAFE_STR
  end

  x.compare!
end

puts "===== Long html_safe String =====\n\n"

Benchmark.ips do |x|
  LONG_HTML_SAFE_STR  = open('http://example.com/').read.html_safe

  x.report 'CGI::escapeHTML' do
    CGI::escapeHTML LONG_HTML_SAFE_STR
  end

  x.report 'ERB::Util.html_escape' do
    ERB::Util.html_escape LONG_HTML_SAFE_STR
  end

  x.report 'Rack::Utils.escape_html' do
    Rack::Utils.escape_html LONG_HTML_SAFE_STR
  end

  x.compare!
end

__END__


===== Short String =====
Comparison:
ERB::Util.html_escape: 113217.7 i/s
CGI::escapeHTML: 110218.2 i/s - 1.03x slower
Rack::Utils.escape_html: 81503.8 i/s - 1.39x slower

===== Long String =====
Comparison:
ERB::Util.html_escape: 25110.7 i/s
CGI::escapeHTML: 24430.1 i/s - 1.03x slower
Rack::Utils.escape_html: 16207.2 i/s - 1.55x slower

===== Short HTML Safe String =====
Comparison:
ERB::Util.html_escape: 2772776.1 i/s
CGI::escapeHTML: 106256.2 i/s - 26.10x slower
Rack::Utils.escape_html: 72086.8 i/s - 38.46x slower

===== Long HTML Safe String =====
Comparison:
ERB::Util.html_escape: 2749941.1 i/s
CGI::escapeHTML: 24777.1 i/s - 110.99x slower
Rack::Utils.escape_html: 16229.5 i/s - 169.44x slower

Rails HTTP Request IDs

The HTTP Request IDs makes it easy to trace requests from end-to-end in the stack and to identify individual requests in mixed logs like Syslog.

Rails 3.2 introduced the ActionDispatch::RequestId middleware that make a unique X-Request-Id header avariable to the response.

For example: curl -I http://sample.dev/

1
2
3
4
5
6
HTTP/1.1 200 OK
...
X-Request-Id: ddaa28e2-3395-4e66-9ca7-48480882a1df
X-Runtime: 0.045724
Date: Fri, 04 Jul 2014 03:23:43 GMT
Connection: close

To show this request ID in with your application logs, add this line to your config/environments/production.rb

1
config.log_tags = [:uuid]

The logs will then be tagged with the Request ID:

1
2
3
4
5
6
7
I, [2014-07-04T11:23:43.752028 #33305]  INFO -- : [ddaa28e2-3395-4e66-9ca7-48480882a1df] Started HEAD "/" for 127.0.0.1 at 2014-07-04 11:23:43 +0800
I, [2014-07-04T11:23:43.755366 #33305]  INFO -- : [ddaa28e2-3395-4e66-9ca7-48480882a1df] Processing by StaticPagesController#home as */*
I, [2014-07-04T11:23:43.759832 #33305]  INFO -- : [ddaa28e2-3395-4e66-9ca7-48480882a1df]   Rendered static_pages/home.html.erb within layouts/application (0.2ms)
I, [2014-07-04T11:23:43.791258 #33305]  INFO -- : [ddaa28e2-3395-4e66-9ca7-48480882a1df]   Rendered layouts/_shim.html.erb (0.0ms)
I, [2014-07-04T11:23:43.793947 #33305]  INFO -- : [ddaa28e2-3395-4e66-9ca7-48480882a1df]   Rendered layouts/_header.html.erb (0.3ms)
I, [2014-07-04T11:23:43.796489 #33305]  INFO -- : [ddaa28e2-3395-4e66-9ca7-48480882a1df]   Rendered layouts/_footer.html.erb (0.2ms)
I, [2014-07-04T11:23:43.797112 #33305]  INFO -- : [ddaa28e2-3395-4e66-9ca7-48480882a1df] Completed 200 OK in 42ms (Views: 41.2ms | ActiveRecord: 0.0ms)

References:

  1. http://guides.rubyonrails.org/3_2_release_notes.html#action-dispatch
  2. https://devcenter.heroku.com/articles/http-request-id

Microsoft Excel Issues “File error: data may have been lost”

Last week, We involve a function for users to exports their orders into a spreadsheet document.

We using the spreadsheet gem to modify an existing template spreadsheet. But when opening the modified spreadsheets by Microsoft Excel, it issues an error:

File error: data may have been lost

After some google search, I was answered to set the encoding explictly:

1
Spreadsheet.client_encoding = 'UTF-16LE'

But it doesn’t works, WTF!

Finally, I decide to create a new spreadsheet and set cell format by hand instead of modify the existing template spreadsheet document. It’s a painful task. The spreadsheet comes up just fine without error.

Even though it doesn’t elegant, we can get ride of that annoying error.

Resolving Vim Key Mapping Conflict

Ack.vim is a plugin for the Perl CLI script ack which is a replacement of grep. It provides a front for running ack from vim.

By default, It will search recursively under the current directory. It’s not convenient to search of a project.

Fortunately, there is a plugin vim-rooter which will changes the working directory to the project root automatically.

I use Janus for my Vim. So I git clone it to ~/.janus directory. It works great, but if I open Vim from the terminal, I got a key mapping conflict error message:

1
2
3
Error detected while processing /Users/hbin/.janus/vim-rooter/plugin/rooter.vim:
line  159:
E227: mapping already exists for ,cd

That’s because Janus mapped <leader>cd to changes the path to the active buffer’s file, and the vim-rooter also try to map <leader>cd to <Plug>RooterChangeToRootDirectory.

Here is the source

1
2
3
if !hasmapto("<Plug>RooterChangeToRootDirectory")
  map <silent> <unique> <Leader>cd <Plug>RooterChangeToRootDirectory
endif

The Solution is simple, just create a mapping to <Plug>RooterChangeToRootDirectory:

1
nnoremap <leader>cr <Plug>RooterChangeToRootDirectory

References:

  1. http://vim.wikia.com/wiki/Mapping_keys_in_Vim_-_Tutorial_(Part_1)
  2. http://stackoverflow.com/questions/3776117/what-is-the-difference-between-the-remap-noremap-nnoremap-and-vnoremap-mapping

Enjoy!

The smart-shift package released!

Smart Shift is a minor mode for conveniently shift the line/region to the left/right by the current major mode indentation width.

Installation

Melpa

Once you have setup Melpa you can use package-install command to install. The package name is smart-shift.

Manual

1
2
3
(add-to-list 'load-path "/path/to/smart-shift")
(require 'smart-shift)
(global-smart-shift-mode 1)

Customizing

Smart Shift will infer the indentation level of current major mode, if none of major modes listed below match, use the tab-width as default.

It can also be set to a number explictly.

1
(setq smart-shift-indentation-level 2)

Or, for some major mode we haven’t support, add following snippets to your config file. Test it and send a PR.

1
2
3
4
(eval-after-load 'your-major-mode
  '(progn
     (add-to-list 'smart-shift-mode-alist
                  '(major-mode-or-derived-mode . customize-base-offset))))

Supported major modes

  • lisp-mode
  • emacs-lisp-mode
  • c-mode
  • c++-mode
  • objc-mode
  • java-mode
  • idl-mode
  • pike-mode
  • awk-mode
  • ruby-mode
  • python-mode
  • swift-mode
  • js-mode
  • js2-mode
  • coffee-mode
  • css-mode
  • scss-mode
  • slim-mode
  • html-mode
  • web-mode
  • sh-mode
  • yaml-mode
  • text-mode
  • markdown-mode
  • fundamental-mode

Interactive commands

Command Keybinding Description
smart-shift-left C-c [ Shift the line or region ARG times to the left.
smart-shift-right C-c ] Shift the line or region ARG times to the right.

After invoking smart-shift-left or smart-shift-right the first time, you can simply hit [ or ] to continuously shift to left or right, respectively.

If you use the key-chord like me. I strongly recommend you add the following snippets:

1
2
(key-chord-define-global "<<" 'smart-shift-left)
(key-chord-define-global ">>" 'smart-shift-right)

Contribute

Repo is here, forks and pull requests are welcome!