Last active
August 29, 2015 13:59
-
-
Save mieko/10577913 to your computer and use it in GitHub Desktop.
Rails-style ERB output escaping for Opal
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# Implement automatic output escaping for ERB. It works a lot like Rails | |
# | |
# Check out this article by Yehuda Katz to get the idea: | |
# http://yehudakatz.com/2010/02/01/safebuffers-and-rails-3-0/ | |
# | |
# Effectively any generated output is escaped unless it is html_safe? | |
# | |
# Nothing is safe except a few built-in classes, and Dirt::SafeString. | |
# | |
# You can generate a Dirt::SafeString from any object by calling #html_safe. | |
# The result of its #to_s is used to generate a new SafeString. | |
# | |
# As to not interfere with other users of ERB, use Template#safe_render instead | |
# of Template#render to get the safe-by-default behaviour. | |
require 'erb' | |
require 'template' | |
# By default, nothing is safe. | |
class BasicObject | |
def html_safe? | |
false | |
end | |
# But we can generate a marked safe version with html_safe | |
def html_safe | |
::Dirt::SafeString.new(to_s) | |
end | |
end | |
# to_s on instances of the following classes cannot generate characters that | |
# require escaping, so we consider them safe. | |
[Boolean, NilClass, Numeric].each do |cls| | |
cls.define_method(:html_safe?) { true } | |
end | |
module Dirt | |
class SafeString < String | |
def html_safe? | |
true | |
end | |
def html_safe | |
self | |
end | |
# SafeString + (an html_safe? object) returns another SafeString. | |
# Anything else returns a String. | |
def +(other) | |
result_cls = other.html_safe? ? SafeString : String | |
result_cls.new(to_s + other.to_s) | |
end | |
alias_method :concat, :+ | |
end | |
end | |
class Template | |
# SafeOutputBuffer behaves like OutputBuffer, but escapes unsafe values | |
class SafeOutputBuffer < OutputBuffer | |
def append=(value) | |
super(value.html_safe? ? value : ::ERB::Util.html_escape(value.to_s)) | |
end | |
end | |
# render_safe acts as render, but uses a SafeOutputBuffer instead of an | |
# OutputBuffer | |
def render_safe(ctx = self) | |
ctx.instance_exec(SafeOutputBuffer.new, &body) | |
end | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment