2012-11-09 09:33:11 -05:00
# -*- coding: us-ascii -*-
2017-10-21 11:02:46 -04:00
# frozen_string_literal: true
2004-11-25 10:23:19 -05:00
# = ERB -- Ruby Templating
#
# Author:: Masatoshi SEKI
2011-05-14 14:24:11 -04:00
# Documentation:: James Edward Gray II, Gavin Sinclair, and Simon Chiang
2004-11-25 10:23:19 -05:00
#
# See ERB for primary documentation and ERB::Util for a couple of utility
# routines.
#
# Copyright (c) 1999-2000,2002,2003 Masatoshi SEKI
#
2002-11-17 11:11:40 -05:00
# You can redistribute it and/or modify it under the same terms as Ruby.
2012-08-13 00:17:00 -04:00
require " cgi/util "
2004-11-25 10:23:19 -05:00
#
# = ERB -- Ruby Templating
#
# == Introduction
#
# ERB provides an easy to use but powerful templating system for Ruby. Using
# ERB, actual Ruby code can be added to any plain text document for the
# purposes of generating document information details and/or flow control.
#
# A very simple example is this:
2009-03-05 22:56:38 -05:00
#
2004-11-25 10:23:19 -05:00
# require 'erb'
#
# x = 42
# template = ERB.new <<-EOF
# The value of x is: <%= x %>
# EOF
# puts template.result(binding)
#
# <em>Prints:</em> The value of x is: 42
#
# More complex examples are given below.
#
#
# == Recognized Tags
#
# ERB recognizes certain tags in the provided template and converts them based
# on the rules below:
#
# <% Ruby code -- inline with output %>
# <%= Ruby expression -- replace with result %>
# <%# comment -- ignored -- useful in testing %>
# % a line of Ruby code -- treated as <% line %> (optional -- see ERB.new)
# %% replaced with % if first thing on a line and % processing is used
# <%% or %%> -- replace with <% or %> respectively
#
# All other text is passed through ERB filtering unchanged.
#
#
# == Options
#
# There are several settings you can change when you use ERB:
# * the nature of the tags that are recognized;
# * the value of <tt>$SAFE</tt> under which the template is run;
# * the binding used to resolve local variables in the template.
#
# See the ERB.new and ERB#result methods for more detail.
#
2008-12-29 04:26:34 -05:00
# == Character encodings
#
2013-07-18 09:50:32 -04:00
# ERB (or Ruby code generated by ERB) returns a string in the same
2008-12-29 04:26:34 -05:00
# character encoding as the input string. When the input string has
# a magic comment, however, it returns a string in the encoding specified
# by the magic comment.
#
2014-07-25 03:55:58 -04:00
# # -*- coding: utf-8 -*-
2008-12-29 04:26:34 -05:00
# require 'erb'
#
# template = ERB.new <<EOF
# <%#-*- coding: Big5 -*-%>
# \_\_ENCODING\_\_ is <%= \_\_ENCODING\_\_ %>.
# EOF
# puts template.result
#
# <em>Prints:</em> \_\_ENCODING\_\_ is Big5.
#
2004-11-25 10:23:19 -05:00
#
# == Examples
#
# === Plain Text
#
# ERB is useful for any generic templating situation. Note that in this example, we use the
# convenient "% at start of line" tag, and we quote the template literally with
# <tt>%q{...}</tt> to avoid trouble with the backslash.
#
# require "erb"
2009-03-05 22:56:38 -05:00
#
2004-11-25 10:23:19 -05:00
# # Create template.
# template = %q{
# From: James Edward Gray II <james@grayproductions.net>
# To: <%= to %>
# Subject: Addressing Needs
2009-03-05 22:56:38 -05:00
#
2004-11-25 10:23:19 -05:00
# <%= to[/\w+/] %>:
2009-03-05 22:56:38 -05:00
#
2004-11-25 10:23:19 -05:00
# Just wanted to send a quick note assuring that your needs are being
# addressed.
2009-03-05 22:56:38 -05:00
#
2004-11-25 10:23:19 -05:00
# I want you to know that my team will keep working on the issues,
# especially:
2009-03-05 22:56:38 -05:00
#
2004-11-25 10:23:19 -05:00
# <%# ignore numerous minor requests -- focus on priorities %>
# % priorities.each do |priority|
# * <%= priority %>
# % end
2009-03-05 22:56:38 -05:00
#
2004-11-25 10:23:19 -05:00
# Thanks for your patience.
2009-03-05 22:56:38 -05:00
#
2004-11-25 10:23:19 -05:00
# James Edward Gray II
# }.gsub(/^ /, '')
2009-03-05 22:56:38 -05:00
#
2018-02-22 08:28:25 -05:00
# message = ERB.new(template, trim_mode: "%<>")
2009-03-05 22:56:38 -05:00
#
2004-11-25 10:23:19 -05:00
# # Set up template data.
# to = "Community Spokesman <spokesman@ruby_community.org>"
# priorities = [ "Run Ruby Quiz",
# "Document Modules",
# "Answer Questions on Ruby Talk" ]
2009-03-05 22:56:38 -05:00
#
2004-11-25 10:23:19 -05:00
# # Produce result.
# email = message.result
# puts email
#
# <i>Generates:</i>
#
# From: James Edward Gray II <james@grayproductions.net>
# To: Community Spokesman <spokesman@ruby_community.org>
# Subject: Addressing Needs
2009-03-05 22:56:38 -05:00
#
2004-11-25 10:23:19 -05:00
# Community:
2009-03-05 22:56:38 -05:00
#
2004-11-25 10:23:19 -05:00
# Just wanted to send a quick note assuring that your needs are being addressed.
2009-03-05 22:56:38 -05:00
#
2004-11-25 10:23:19 -05:00
# I want you to know that my team will keep working on the issues, especially:
2009-03-05 22:56:38 -05:00
#
2004-11-25 10:23:19 -05:00
# * Run Ruby Quiz
# * Document Modules
# * Answer Questions on Ruby Talk
2009-03-05 22:56:38 -05:00
#
2004-11-25 10:23:19 -05:00
# Thanks for your patience.
2009-03-05 22:56:38 -05:00
#
2004-11-25 10:23:19 -05:00
# James Edward Gray II
#
# === Ruby in HTML
#
# ERB is often used in <tt>.rhtml</tt> files (HTML with embedded Ruby). Notice the need in
# this example to provide a special binding when the template is run, so that the instance
# variables in the Product object can be resolved.
#
# require "erb"
2009-03-05 22:56:38 -05:00
#
2004-11-25 10:23:19 -05:00
# # Build template data class.
# class Product
# def initialize( code, name, desc, cost )
# @code = code
# @name = name
# @desc = desc
# @cost = cost
2009-03-05 22:56:38 -05:00
#
2004-11-25 10:23:19 -05:00
# @features = [ ]
# end
2009-03-05 22:56:38 -05:00
#
2004-11-25 10:23:19 -05:00
# def add_feature( feature )
# @features << feature
# end
2009-03-05 22:56:38 -05:00
#
2004-11-25 10:23:19 -05:00
# # Support templating of member data.
# def get_binding
# binding
# end
2009-03-05 22:56:38 -05:00
#
2004-11-25 10:23:19 -05:00
# # ...
# end
2009-03-05 22:56:38 -05:00
#
2004-11-25 10:23:19 -05:00
# # Create template.
# template = %{
# <html>
# <head><title>Ruby Toys -- <%= @name %></title></head>
# <body>
2009-03-05 22:56:38 -05:00
#
2004-11-25 10:23:19 -05:00
# <h1><%= @name %> (<%= @code %>)</h1>
# <p><%= @desc %></p>
2009-03-05 22:56:38 -05:00
#
2004-11-25 10:23:19 -05:00
# <ul>
# <% @features.each do |f| %>
# <li><b><%= f %></b></li>
# <% end %>
# </ul>
2009-03-05 22:56:38 -05:00
#
2004-11-25 10:23:19 -05:00
# <p>
# <% if @cost < 10 %>
# <b>Only <%= @cost %>!!!</b>
# <% else %>
# Call for a price, today!
# <% end %>
# </p>
2009-03-05 22:56:38 -05:00
#
2004-11-25 10:23:19 -05:00
# </body>
# </html>
# }.gsub(/^ /, '')
2009-03-05 22:56:38 -05:00
#
2004-11-25 10:23:19 -05:00
# rhtml = ERB.new(template)
2009-03-05 22:56:38 -05:00
#
2004-11-25 10:23:19 -05:00
# # Set up template data.
# toy = Product.new( "TZ-1002",
# "Rubysapien",
# "Geek's Best Friend! Responds to Ruby commands...",
# 999.95 )
# toy.add_feature("Listens for verbal commands in the Ruby language!")
# toy.add_feature("Ignores Perl, Java, and all C variants.")
# toy.add_feature("Karate-Chop Action!!!")
# toy.add_feature("Matz signature on left leg.")
# toy.add_feature("Gem studded eyes... Rubies, of course!")
2009-03-05 22:56:38 -05:00
#
2004-11-25 10:23:19 -05:00
# # Produce result.
# rhtml.run(toy.get_binding)
#
# <i>Generates (some blank lines removed):</i>
#
# <html>
# <head><title>Ruby Toys -- Rubysapien</title></head>
# <body>
2009-03-05 22:56:38 -05:00
#
2004-11-25 10:23:19 -05:00
# <h1>Rubysapien (TZ-1002)</h1>
# <p>Geek's Best Friend! Responds to Ruby commands...</p>
2009-03-05 22:56:38 -05:00
#
2004-11-25 10:23:19 -05:00
# <ul>
# <li><b>Listens for verbal commands in the Ruby language!</b></li>
# <li><b>Ignores Perl, Java, and all C variants.</b></li>
# <li><b>Karate-Chop Action!!!</b></li>
# <li><b>Matz signature on left leg.</b></li>
# <li><b>Gem studded eyes... Rubies, of course!</b></li>
# </ul>
2009-03-05 22:56:38 -05:00
#
2004-11-25 10:23:19 -05:00
# <p>
# Call for a price, today!
# </p>
2009-03-05 22:56:38 -05:00
#
2004-11-25 10:23:19 -05:00
# </body>
# </html>
#
2009-03-05 22:56:38 -05:00
#
2004-11-25 10:23:19 -05:00
# == Notes
#
2019-10-26 02:34:14 -04:00
# There are a variety of templating solutions available in various Ruby projects.
# For example, RDoc, distributed with Ruby, uses its own template engine, which
# can be reused elsewhere.
2004-11-25 10:23:19 -05:00
#
2019-10-26 02:34:14 -04:00
# Other popular engines could be found in the corresponding
# {Category}[https://www.ruby-toolbox.com/categories/template_engines] of
# The Ruby Toolbox.
2004-11-25 10:23:19 -05:00
#
2002-11-17 11:11:40 -05:00
class ERB
2013-01-25 22:58:33 -05:00
Revision = '$Date:: $' # :nodoc: #'
2002-11-17 11:11:40 -05:00
2004-11-25 10:23:19 -05:00
# Returns revision information for the erb.rb module.
2002-11-17 11:11:40 -05:00
def self . version
2018-02-22 08:28:25 -05:00
" erb.rb [2.2.0 #{ ERB :: Revision . split [ 1 ] } ] "
2002-11-17 11:11:40 -05:00
end
end
2004-11-25 10:23:19 -05:00
#--
2002-11-17 11:11:40 -05:00
# ERB::Compiler
class ERB
2011-05-14 14:24:11 -04:00
# = ERB::Compiler
2011-05-15 07:55:52 -04:00
#
2011-05-14 14:24:11 -04:00
# Compiles ERB templates into Ruby code; the compiled code produces the
# template result when evaluated. ERB::Compiler provides hooks to define how
# generated output is handled.
#
# Internally ERB does something like this to generate the code returned by
# ERB#src:
#
# compiler = ERB::Compiler.new('<>')
2017-05-26 23:06:55 -04:00
# compiler.pre_cmd = ["_erbout=+''"]
2017-05-15 09:38:02 -04:00
# compiler.put_cmd = "_erbout.<<"
# compiler.insert_cmd = "_erbout.<<"
2011-05-14 14:24:11 -04:00
# compiler.post_cmd = ["_erbout"]
#
# code, enc = compiler.compile("Got <%= obj %>!\n")
# puts code
#
# <i>Generates</i>:
#
# #coding:UTF-8
2017-12-27 07:40:03 -05:00
# _erbout=+''; _erbout.<< "Got ".freeze; _erbout.<<(( obj ).to_s); _erbout.<< "!\n".freeze; _erbout
2011-05-14 14:24:11 -04:00
#
# By default the output is sent to the print method. For example:
#
# compiler = ERB::Compiler.new('<>')
# code, enc = compiler.compile("Got <%= obj %>!\n")
# puts code
#
# <i>Generates</i>:
#
# #coding:UTF-8
2017-12-27 07:40:03 -05:00
# print "Got ".freeze; print(( obj ).to_s); print "!\n".freeze
2011-05-14 14:24:11 -04:00
#
# == Evaluation
#
# The compiled code can be used in any context where the names in the code
# correctly resolve. Using the last example, each of these print 'Got It!'
#
# Evaluate using a variable:
#
# obj = 'It'
# eval code
2011-05-15 07:55:52 -04:00
#
2011-05-14 14:24:11 -04:00
# Evaluate using an input:
#
# mod = Module.new
# mod.module_eval %{
# def get(obj)
# #{code}
# end
# }
# extend mod
# get('It')
#
# Evaluate using an accessor:
#
# klass = Class.new Object
# klass.class_eval %{
# attr_accessor :obj
# def initialize(obj)
# @obj = obj
# end
# def get_it
# #{code}
# end
# }
# klass.new('It').get_it
#
# Good! See also ERB#def_method, ERB#def_module, and ERB#def_class.
2011-05-24 19:22:40 -04:00
class Compiler # :nodoc:
2004-11-25 10:23:19 -05:00
class PercentLine # :nodoc:
2003-07-25 18:03:52 -04:00
def initialize ( str )
@value = str
end
attr_reader :value
alias :to_s :value
end
2004-11-25 10:23:19 -05:00
class Scanner # :nodoc:
2003-07-30 23:42:17 -04:00
@scanner_map = { }
2016-11-05 12:56:52 -04:00
class << self
def register_scanner ( klass , trim_mode , percent )
@scanner_map [ [ trim_mode , percent ] ] = klass
end
alias :regist_scanner :register_scanner
2003-07-30 23:42:17 -04:00
end
def self . default_scanner = ( klass )
2011-05-18 17:19:18 -04:00
@default_scanner = klass
2003-07-30 23:42:17 -04:00
end
def self . make_scanner ( src , trim_mode , percent )
2011-05-18 17:19:18 -04:00
klass = @scanner_map . fetch ( [ trim_mode , percent ] , @default_scanner )
klass . new ( src , trim_mode , percent )
2003-07-30 23:42:17 -04:00
end
2017-05-21 23:56:16 -04:00
DEFAULT_STAGS = %w( <%% <%= <% # <% ) . freeze
DEFAULT_ETAGS = %w( %%> %> ) . freeze
2003-07-30 23:42:17 -04:00
def initialize ( src , trim_mode , percent )
2011-05-18 17:19:18 -04:00
@src = src
@stag = nil
2017-05-21 23:56:16 -04:00
@stags = DEFAULT_STAGS
@etags = DEFAULT_ETAGS
2003-01-20 06:32:19 -05:00
end
2003-07-23 05:47:16 -04:00
attr_accessor :stag
2016-01-02 02:19:58 -05:00
attr_reader :stags , :etags
2003-07-23 05:47:16 -04:00
def scan ; end
end
2003-01-20 06:32:19 -05:00
2004-11-25 10:23:19 -05:00
class TrimScanner < Scanner # :nodoc:
2003-07-25 18:03:52 -04:00
def initialize ( src , trim_mode , percent )
2011-05-18 17:19:18 -04:00
super
@trim_mode = trim_mode
@percent = percent
if @trim_mode == '>'
2017-05-20 13:36:09 -04:00
@scan_reg = / (.*?)(%> \ r? \ n| #{ ( stags + etags ) . join ( '|' ) } | \ n| \ z) /m
2011-05-18 17:19:18 -04:00
@scan_line = self . method ( :trim_line1 )
elsif @trim_mode == '<>'
2017-05-20 12:50:33 -04:00
@scan_reg = / (.*?)(%> \ r? \ n| #{ ( stags + etags ) . join ( '|' ) } | \ n| \ z) /m
2011-05-18 17:19:18 -04:00
@scan_line = self . method ( :trim_line2 )
elsif @trim_mode == '-'
2017-05-20 13:17:22 -04:00
@scan_reg = / (.*?)(^[ \ t]*<% \ -|<% \ -|-%> \ r? \ n|-%>| #{ ( stags + etags ) . join ( '|' ) } | \ z) /m
2011-05-18 17:19:18 -04:00
@scan_line = self . method ( :explicit_trim_line )
else
2016-01-02 02:19:58 -05:00
@scan_reg = / (.*?)( #{ ( stags + etags ) . join ( '|' ) } | \ n| \ z) /m
2011-05-18 17:19:18 -04:00
@scan_line = self . method ( :scan_line )
end
2003-01-20 06:32:19 -05:00
end
2009-03-05 22:56:38 -05:00
2003-07-23 05:47:16 -04:00
def scan ( & block )
2011-05-18 17:19:18 -04:00
@stag = nil
if @percent
@src . each_line do | line |
percent_line ( line , & block )
end
else
2009-01-03 10:36:14 -05:00
@scan_line . call ( @src , & block )
2011-05-18 17:19:18 -04:00
end
nil
2003-01-20 06:32:19 -05:00
end
2003-07-23 05:47:16 -04:00
def percent_line ( line , & block )
2011-05-18 17:19:18 -04:00
if @stag || line [ 0 ] != ?%
return @scan_line . call ( line , & block )
end
line [ 0 ] = ''
if line [ 0 ] == ?%
@scan_line . call ( line , & block )
else
2003-07-25 18:03:52 -04:00
yield ( PercentLine . new ( line . chomp ) )
2011-05-18 17:19:18 -04:00
end
2003-07-23 05:47:16 -04:00
end
def scan_line ( line )
2016-01-02 02:19:58 -05:00
line . scan ( @scan_reg ) do | tokens |
2009-01-03 10:36:14 -05:00
tokens . each do | token |
next if token . empty?
yield ( token )
end
2011-05-18 17:19:18 -04:00
end
2003-07-23 05:47:16 -04:00
end
2003-07-30 23:42:17 -04:00
def trim_line1 ( line )
2016-01-02 02:19:58 -05:00
line . scan ( @scan_reg ) do | tokens |
2009-01-03 10:36:14 -05:00
tokens . each do | token |
next if token . empty?
2017-05-20 13:36:09 -04:00
if token == " %> \n " || token == " %> \r \n "
2009-01-03 10:36:14 -05:00
yield ( '%>' )
yield ( :cr )
else
yield ( token )
end
end
2011-05-18 17:19:18 -04:00
end
2003-07-30 23:42:17 -04:00
end
def trim_line2 ( line )
2011-05-18 17:19:18 -04:00
head = nil
2016-01-02 02:19:58 -05:00
line . scan ( @scan_reg ) do | tokens |
2009-01-03 10:36:14 -05:00
tokens . each do | token |
next if token . empty?
head = token unless head
2017-05-20 12:50:33 -04:00
if token == " %> \n " || token == " %> \r \n "
2009-01-03 10:36:14 -05:00
yield ( '%>' )
if is_erb_stag? ( head )
yield ( :cr )
else
yield ( " \n " )
end
head = nil
else
yield ( token )
head = nil if token == " \n "
end
end
2011-05-18 17:19:18 -04:00
end
2003-07-23 05:47:16 -04:00
end
2003-07-30 23:42:17 -04:00
def explicit_trim_line ( line )
2016-01-02 02:19:58 -05:00
line . scan ( @scan_reg ) do | tokens |
2009-01-03 10:36:14 -05:00
tokens . each do | token |
next if token . empty?
if @stag . nil? && / [ \ t]*<%- / =~ token
yield ( '<%' )
2017-05-20 13:17:22 -04:00
elsif @stag && ( token == " -%> \n " || token == " -%> \r \n " )
2009-01-03 10:36:14 -05:00
yield ( '%>' )
yield ( :cr )
elsif @stag && token == '-%>'
yield ( '%>' )
else
yield ( token )
end
end
end
2003-07-30 23:42:17 -04:00
end
2003-07-23 05:47:16 -04:00
ERB_STAG = %w( <%= <% # <% )
def is_erb_stag? ( s )
2011-05-18 17:19:18 -04:00
ERB_STAG . member? ( s )
2002-11-17 11:11:40 -05:00
end
end
2003-07-30 23:42:17 -04:00
Scanner . default_scanner = TrimScanner
begin
require 'strscan'
2017-05-20 12:20:07 -04:00
rescue LoadError
else
2017-05-20 10:55:33 -04:00
class SimpleScanner < Scanner # :nodoc:
2003-07-30 23:42:17 -04:00
def scan
2017-05-21 23:56:16 -04:00
stag_reg = ( stags == DEFAULT_STAGS ) ? / (.*?)(<%[%= # ]?| \ z) /m : / (.*?)( #{ stags . join ( '|' ) } | \ z) /m
etag_reg = ( etags == DEFAULT_ETAGS ) ? / (.*?)(%%?>| \ z) /m : / (.*?)( #{ etags . join ( '|' ) } | \ z) /m
2003-07-30 23:42:17 -04:00
scanner = StringScanner . new ( @src )
while ! scanner . eos?
scanner . scan ( @stag ? etag_reg : stag_reg )
2009-01-03 10:36:14 -05:00
yield ( scanner [ 1 ] )
yield ( scanner [ 2 ] )
2003-07-30 23:42:17 -04:00
end
end
end
2017-08-04 07:59:59 -04:00
Scanner . register_scanner ( SimpleScanner , nil , false )
2017-05-20 10:55:33 -04:00
2004-11-25 10:23:19 -05:00
class ExplicitScanner < Scanner # :nodoc:
2011-05-18 17:19:18 -04:00
def scan
2016-01-02 02:19:58 -05:00
stag_reg = / (.*?)(^[ \ t]*<%-|<%-| #{ stags . join ( '|' ) } | \ z) /m
etag_reg = / (.*?)(-%>| #{ etags . join ( '|' ) } | \ z) /m
2003-07-30 23:42:17 -04:00
scanner = StringScanner . new ( @src )
while ! scanner . eos?
2011-05-18 17:19:18 -04:00
scanner . scan ( @stag ? etag_reg : stag_reg )
2009-01-03 10:36:14 -05:00
yield ( scanner [ 1 ] )
2003-07-30 23:42:17 -04:00
elem = scanner [ 2 ]
2009-01-03 10:36:14 -05:00
if / [ \ t]*<%- / =~ elem
yield ( '<%' )
elsif elem == '-%>'
2011-05-18 17:19:18 -04:00
yield ( '%>' )
2017-05-20 13:17:22 -04:00
yield ( :cr ) if scanner . scan ( / ( \ r? \ n| \ z) / )
2011-05-18 17:19:18 -04:00
else
yield ( elem )
end
2003-07-30 23:42:17 -04:00
end
end
end
2017-08-04 07:59:59 -04:00
Scanner . register_scanner ( ExplicitScanner , '-' , false )
2003-07-30 23:42:17 -04:00
end
2002-11-17 11:11:40 -05:00
2004-11-25 10:23:19 -05:00
class Buffer # :nodoc:
2016-01-29 00:16:29 -05:00
def initialize ( compiler , enc = nil , frozen = nil )
2011-05-18 17:19:18 -04:00
@compiler = compiler
@line = [ ]
2017-10-21 11:02:46 -04:00
@script = + ''
2016-01-29 00:16:29 -05:00
@script << " # coding: #{ enc } \n " if enc
@script << " # frozen-string-literal: #{ frozen } \n " unless frozen . nil?
2011-05-18 17:19:18 -04:00
@compiler . pre_cmd . each do | x |
push ( x )
end
2003-07-23 05:47:16 -04:00
end
attr_reader :script
def push ( cmd )
2011-05-18 17:19:18 -04:00
@line << cmd
2003-07-23 05:47:16 -04:00
end
2009-03-05 22:56:38 -05:00
2003-07-23 05:47:16 -04:00
def cr
2011-05-18 17:19:18 -04:00
@script << ( @line . join ( '; ' ) )
@line = [ ]
@script << " \n "
2003-07-23 05:47:16 -04:00
end
2009-03-05 22:56:38 -05:00
2003-07-23 05:47:16 -04:00
def close
2011-05-18 17:19:18 -04:00
return unless @line
@compiler . post_cmd . each do | x |
push ( x )
end
@script << ( @line . join ( '; ' ) )
@line = nil
2003-01-20 06:32:19 -05:00
end
end
2012-12-04 10:10:17 -05:00
def add_put_cmd ( out , content )
2017-12-27 07:40:03 -05:00
out . push ( " #{ @put_cmd } #{ content . dump } .freeze #{ " \n " * content . count ( " \n " ) } " )
2012-12-04 10:10:17 -05:00
end
2012-12-04 23:08:17 -05:00
2012-12-04 10:10:17 -05:00
def add_insert_cmd ( out , content )
2015-12-20 01:36:57 -05:00
out . push ( " #{ @insert_cmd } (( #{ content } ).to_s) " )
2012-12-04 10:10:17 -05:00
end
2011-05-14 14:24:11 -04:00
# Compiles an ERB template into Ruby code. Returns an array of the code
# and encoding like ["code", Encoding].
2002-11-17 11:11:40 -05:00
def compile ( s )
2008-12-29 04:26:34 -05:00
enc = s . encoding
raise ArgumentError , " #{ enc } is not ASCII compatible " if enc . dummy?
2013-06-02 02:06:00 -04:00
s = s . b # see String#b
2016-01-29 00:16:29 -05:00
magic_comment = detect_magic_comment ( s , enc )
out = Buffer . new ( self , * magic_comment )
2003-07-23 05:47:16 -04:00
2017-10-21 11:02:46 -04:00
self . content = + ''
2009-01-03 10:36:14 -05:00
scanner = make_scanner ( s )
2003-07-23 05:47:16 -04:00
scanner . scan do | token |
2009-03-05 22:56:38 -05:00
next if token . nil?
2009-01-03 10:36:14 -05:00
next if token == ''
2011-05-18 17:19:18 -04:00
if scanner . stag . nil?
2016-01-02 02:19:58 -05:00
compile_stag ( token , out , scanner )
2011-05-18 17:19:18 -04:00
else
2016-01-02 02:19:58 -05:00
compile_etag ( token , out , scanner )
2011-05-18 17:19:18 -04:00
end
2002-11-17 11:11:40 -05:00
end
2012-12-04 10:10:17 -05:00
add_put_cmd ( out , content ) if content . size > 0
2003-07-23 05:47:16 -04:00
out . close
2016-01-29 00:16:29 -05:00
return out . script , * magic_comment
2003-07-23 05:47:16 -04:00
end
2016-01-02 02:19:58 -05:00
def compile_stag ( stag , out , scanner )
case stag
when PercentLine
add_put_cmd ( out , content ) if content . size > 0
2017-10-21 11:02:46 -04:00
self . content = + ''
2016-01-02 02:19:58 -05:00
out . push ( stag . to_s )
out . cr
when :cr
out . cr
when '<%' , '<%=' , '<%#'
scanner . stag = stag
add_put_cmd ( out , content ) if content . size > 0
2017-10-21 11:02:46 -04:00
self . content = + ''
2016-01-02 02:19:58 -05:00
when " \n "
content << " \n "
add_put_cmd ( out , content )
2017-10-21 11:02:46 -04:00
self . content = + ''
2016-01-02 02:19:58 -05:00
when '<%%'
content << '<%'
else
content << stag
end
end
def compile_etag ( etag , out , scanner )
case etag
when '%>'
compile_content ( scanner . stag , out )
scanner . stag = nil
2017-10-21 11:02:46 -04:00
self . content = + ''
2016-01-02 02:19:58 -05:00
when '%%>'
content << '%>'
else
content << etag
end
end
def compile_content ( stag , out )
case stag
when '<%'
if content [ - 1 ] == ?\n
content . chop!
out . push ( content )
out . cr
else
out . push ( content )
end
when '<%='
add_insert_cmd ( out , content )
when '<%#'
2017-12-27 07:40:03 -05:00
# commented out
2016-01-02 02:19:58 -05:00
end
end
2011-05-14 14:24:11 -04:00
def prepare_trim_mode ( mode ) # :nodoc:
2003-07-23 05:47:16 -04:00
case mode
when 1
2011-05-18 17:19:18 -04:00
return [ false , '>' ]
2003-07-23 05:47:16 -04:00
when 2
2011-05-18 17:19:18 -04:00
return [ false , '<>' ]
2018-11-11 19:37:15 -05:00
when 0 , nil
2011-05-18 17:19:18 -04:00
return [ false , nil ]
2003-07-23 05:47:16 -04:00
when String
2018-11-11 19:37:15 -05:00
unless mode . match? ( / \ A(%|-|>|<>){1,2} \ z / )
warn_invalid_trim_mode ( mode , uplevel : 5 )
end
2011-05-18 17:19:18 -04:00
perc = mode . include? ( '%' )
if mode . include? ( '-' )
return [ perc , '-' ]
elsif mode . include? ( '<>' )
return [ perc , '<>' ]
elsif mode . include? ( '>' )
return [ perc , '>' ]
else
[ perc , nil ]
end
2003-07-23 05:47:16 -04:00
else
2018-11-11 19:37:15 -05:00
warn_invalid_trim_mode ( mode , uplevel : 5 )
2011-05-18 17:19:18 -04:00
return [ false , nil ]
2003-07-23 05:47:16 -04:00
end
end
2011-05-14 14:24:11 -04:00
def make_scanner ( src ) # :nodoc:
2003-07-30 23:42:17 -04:00
Scanner . make_scanner ( src , @trim_mode , @percent )
2002-11-17 11:11:40 -05:00
end
2012-12-23 02:13:07 -05:00
# Construct a new compiler using the trim_mode. See ERB::new for available
2011-05-14 14:24:11 -04:00
# trim modes.
2003-01-20 06:32:19 -05:00
def initialize ( trim_mode )
2003-07-23 05:47:16 -04:00
@percent , @trim_mode = prepare_trim_mode ( trim_mode )
2002-11-17 11:11:40 -05:00
@put_cmd = 'print'
2006-01-10 10:21:45 -05:00
@insert_cmd = @put_cmd
2002-11-17 11:11:40 -05:00
@pre_cmd = [ ]
@post_cmd = [ ]
end
2003-07-23 05:47:16 -04:00
attr_reader :percent , :trim_mode
2011-05-14 14:24:11 -04:00
# The command to handle text that ends with a newline
attr_accessor :put_cmd
# The command to handle text that is inserted prior to a newline
attr_accessor :insert_cmd
# An array of commands prepended to compiled code
attr_accessor :pre_cmd
# An array of commands appended to compiled code
attr_accessor :post_cmd
2008-12-29 04:26:34 -05:00
private
2016-01-02 02:19:58 -05:00
# A buffered text in #compile
attr_accessor :content
2016-01-29 00:16:29 -05:00
def detect_magic_comment ( s , enc = nil )
re = @percent ? / \ G(?:<% # (.*)%>|% # (.*) \ n) / : / \ G<% # (.*)%> /
frozen = nil
s . scan ( re ) do
comment = $+
2011-05-18 17:19:18 -04:00
comment = $1 if comment [ / - \ *- \ s*(.*?) \ s*-*-$ / ]
2016-01-29 00:16:29 -05:00
case comment
when %r"coding\s*[=:]\s*([[:alnum:]\-_]+)"
enc = Encoding . find ( $1 . sub ( / -(?:mac|dos|unix) /i , '' ) )
when %r"frozen[-_]string[-_]literal\s*:\s*([[:alnum:]]+)"
frozen = $1
2011-05-18 17:19:18 -04:00
end
2008-12-29 04:26:34 -05:00
end
2016-01-29 00:16:29 -05:00
return enc , frozen
2008-12-29 04:26:34 -05:00
end
2018-11-11 19:37:15 -05:00
def warn_invalid_trim_mode ( mode , uplevel : )
warn " Invalid ERB trim mode: #{ mode . inspect } (trim_mode: nil, 0, 1, 2, or String composed of '%' and/or '-', '>', '<>') " , uplevel : uplevel + 1
end
2002-11-17 11:11:40 -05:00
end
end
2004-11-25 10:23:19 -05:00
#--
2002-11-17 11:11:40 -05:00
# ERB
class ERB
2004-11-25 10:23:19 -05:00
#
# Constructs a new ERB object with the template specified in _str_.
2009-03-05 22:56:38 -05:00
#
2004-11-25 10:23:19 -05:00
# An ERB object works by building a chunk of Ruby code that will output
# the completed template when run. If _safe_level_ is set to a non-nil value,
# ERB code will be run in a separate thread with <b>$SAFE</b> set to the
# provided level.
2009-03-05 22:56:38 -05:00
#
2004-11-25 10:23:19 -05:00
# If _trim_mode_ is passed a String containing one or more of the following
# modifiers, ERB will adjust its code generation as listed:
2009-03-05 22:56:38 -05:00
#
2011-05-18 20:07:25 -04:00
# % enables Ruby code processing for lines beginning with %
# <> omit newline for lines starting with <% and ending in %>
# > omit newline for lines ending in %>
2012-12-23 02:07:18 -05:00
# - omit blank lines ending in -%>
2009-03-05 22:56:38 -05:00
#
2004-11-25 10:23:19 -05:00
# _eoutvar_ can be used to set the name of the variable ERB will build up
# its output in. This is useful when you need to run multiple ERB
# templates through the same binding and/or when you want to control where
# output ends up. Pass the name of the variable to be used inside a String.
#
# === Example
#
# require "erb"
2009-03-05 22:56:38 -05:00
#
2004-11-25 10:23:19 -05:00
# # build data class
# class Listings
# PRODUCT = { :name => "Chicken Fried Steak",
# :desc => "A well messages pattie, breaded and fried.",
# :cost => 9.95 }
2009-03-05 22:56:38 -05:00
#
2004-11-25 10:23:19 -05:00
# attr_reader :product, :price
2009-03-05 22:56:38 -05:00
#
2004-11-25 10:23:19 -05:00
# def initialize( product = "", price = "" )
# @product = product
# @price = price
# end
2009-03-05 22:56:38 -05:00
#
2004-11-25 10:23:19 -05:00
# def build
# b = binding
2008-06-04 05:37:38 -04:00
# # create and run templates, filling member data variables
2018-02-22 08:28:25 -05:00
# ERB.new(<<-'END_PRODUCT'.gsub(/^\s+/, ""), trim_mode: "", eoutvar: "@product").result b
2004-11-25 10:23:19 -05:00
# <%= PRODUCT[:name] %>
# <%= PRODUCT[:desc] %>
# END_PRODUCT
2018-02-22 08:28:25 -05:00
# ERB.new(<<-'END_PRICE'.gsub(/^\s+/, ""), trim_mode: "", eoutvar: "@price").result b
2004-11-25 10:23:19 -05:00
# <%= PRODUCT[:name] %> -- <%= PRODUCT[:cost] %>
# <%= PRODUCT[:desc] %>
# END_PRICE
# end
# end
2009-03-05 22:56:38 -05:00
#
2004-11-25 10:23:19 -05:00
# # setup template data
# listings = Listings.new
# listings.build
2009-03-05 22:56:38 -05:00
#
2004-11-25 10:23:19 -05:00
# puts listings.product + "\n" + listings.price
#
# _Generates_
#
# Chicken Fried Steak
# A well messages pattie, breaded and fried.
2009-03-05 22:56:38 -05:00
#
2004-11-25 10:23:19 -05:00
# Chicken Fried Steak -- 9.95
# A well messages pattie, breaded and fried.
2009-03-05 22:56:38 -05:00
#
2018-02-22 08:28:25 -05:00
def initialize ( str , safe_level = NOT_GIVEN , legacy_trim_mode = NOT_GIVEN , legacy_eoutvar = NOT_GIVEN , trim_mode : nil , eoutvar : '_erbout' )
2018-12-29 02:11:38 -05:00
# Complex initializer for $SAFE deprecation at [Feature #14256]. Use keyword arguments to pass trim_mode or eoutvar.
2018-02-22 08:28:25 -05:00
if safe_level != NOT_GIVEN
2018-12-29 02:26:22 -05:00
warn 'Passing safe_level with the 2nd argument of ERB.new is deprecated. Do not use it, and specify other arguments as keyword arguments.' , uplevel : 1 if $VERBOSE || ! ZERO_SAFE_LEVELS . include? ( safe_level )
2018-02-22 08:28:25 -05:00
else
safe_level = nil
end
if legacy_trim_mode != NOT_GIVEN
2018-12-29 02:11:38 -05:00
warn 'Passing trim_mode with the 3rd argument of ERB.new is deprecated. Use keyword argument like ERB.new(str, trim_mode: ...) instead.' , uplevel : 1 if $VERBOSE
2018-02-22 08:28:25 -05:00
trim_mode = legacy_trim_mode
end
if legacy_eoutvar != NOT_GIVEN
2018-12-29 02:11:38 -05:00
warn 'Passing eoutvar with the 4th argument of ERB.new is deprecated. Use keyword argument like ERB.new(str, eoutvar: ...) instead.' , uplevel : 1 if $VERBOSE
2018-02-22 08:28:25 -05:00
eoutvar = legacy_eoutvar
end
2002-11-17 11:11:40 -05:00
@safe_level = safe_level
2012-12-04 10:10:17 -05:00
compiler = make_compiler ( trim_mode )
2002-11-17 11:11:40 -05:00
set_eoutvar ( compiler , eoutvar )
2016-01-29 00:16:29 -05:00
@src , @encoding , @frozen_string = * compiler . compile ( str )
2003-12-10 04:07:52 -05:00
@filename = nil
2014-12-12 05:31:47 -05:00
@lineno = 0
2019-03-27 23:46:48 -04:00
@_init = self . class . singleton_class
2002-11-17 11:11:40 -05:00
end
2018-02-22 08:28:25 -05:00
NOT_GIVEN = Object . new
private_constant :NOT_GIVEN
2018-12-29 02:26:22 -05:00
ZERO_SAFE_LEVELS = [ 0 , nil ]
private_constant :ZERO_SAFE_LEVELS
2004-11-25 10:23:19 -05:00
2013-01-25 22:58:33 -05:00
##
# Creates a new compiler for ERB. See ERB::Compiler.new for details
2012-12-04 10:10:17 -05:00
def make_compiler ( trim_mode )
ERB :: Compiler . new ( trim_mode )
end
2004-11-25 10:23:19 -05:00
# The Ruby code generated by ERB
2003-12-10 04:07:52 -05:00
attr_reader :src
2004-11-25 10:23:19 -05:00
2014-12-12 05:48:57 -05:00
# The encoding to eval
attr_reader :encoding
2004-11-25 10:23:19 -05:00
# The optional _filename_ argument passed to Kernel#eval when the ERB code
# is run
2003-12-10 04:07:52 -05:00
attr_accessor :filename
2002-11-17 11:11:40 -05:00
2014-12-12 05:31:47 -05:00
# The optional _lineno_ argument passed to Kernel#eval when the ERB code
# is run
attr_accessor :lineno
2019-10-26 02:34:14 -04:00
#
# Sets optional filename and line number that will be used in ERB code
# evaluation and error reporting. See also #filename= and #lineno=
#
# erb = ERB.new('<%= some_x %>')
# erb.render
# # undefined local variable or method `some_x'
# # from (erb):1
#
# erb.location = ['file.erb', 3]
# # All subsequent error reporting would use new location
# erb.render
# # undefined local variable or method `some_x'
# # from file.erb:4
#
2014-12-12 05:31:47 -05:00
def location = ( ( filename , lineno ) )
@filename = filename
@lineno = lineno if lineno
end
2004-11-25 10:23:19 -05:00
#
2012-12-23 02:13:07 -05:00
# Can be used to set _eoutvar_ as described in ERB::new. It's probably
# easier to just use the constructor though, since calling this method
# requires the setup of an ERB _compiler_ object.
2004-11-25 10:23:19 -05:00
#
2002-11-17 11:11:40 -05:00
def set_eoutvar ( compiler , eoutvar = '_erbout' )
2017-05-15 09:38:02 -04:00
compiler . put_cmd = " #{ eoutvar } .<< "
compiler . insert_cmd = " #{ eoutvar } .<< "
2017-05-26 23:06:55 -04:00
compiler . pre_cmd = [ " #{ eoutvar } = +'' " ]
erb.rb: Use script encoding instead of force_encoding
The original intention of introducing `_erbout.force_encoding`
in r21170 was:
- "returns a string in the same character encoding as the input string."
- "When the input string has a magic comment, however, it returns a string
in the encoding specified by the magic comment."
And they are tested by test/erb/test_erb_m17n.rb well and this patch
passes the test.
Since magic comment is always added in ERB compiled code, using ''.dup
instead of String.new will set correct encoding without calling
force_encoding method.
The benchmark results are:
* Before
$ ./ruby benchmark/run.rb --matzruby=./ruby -m bm_app_erb
MatzRuby:
ruby 2.5.0dev (2017-05-26 skip-force-enc.. 58903) [x86_64-linux]
last_commit=Skip force_encoding in compiled code of erb
Ruby:
app_erb:
matz 0.715
* After
$ ./ruby benchmark/run.rb --matzruby=./ruby -m bm_app_erb
MatzRuby:
ruby 2.5.0dev (2017-05-26 skip-force-enc.. 58903) [x86_64-linux]
last_commit=Skip force_encoding in compiled code of erb
Ruby:
app_erb:
matz 0.672
And perf(1) results are:
* Before
$ sudo perf stat ./ruby benchmark/bm_app_erb.rb
Performance counter stats for './ruby benchmark/bm_app_erb.rb':
709.571746 task-clock (msec) # 1.000 CPUs utilized
5 context-switches # 0.007 K/sec
1 cpu-migrations # 0.001 K/sec
1,337 page-faults # 0.002 M/sec
3,088,936,521 cycles # 4.353 GHz
<not supported> stalled-cycles-frontend
<not supported> stalled-cycles-backend
4,849,564,282 instructions # 1.57 insns per cycle
1,027,042,087 branches # 1447.411 M/sec
19,983,456 branch-misses # 1.95% of all branches
0.709747823 seconds time elapsed
* After
$ sudo perf stat ./ruby benchmark/bm_app_erb.rb
Performance counter stats for './ruby benchmark/bm_app_erb.rb':
693.494673 task-clock (msec) # 1.000 CPUs utilized
7 context-switches # 0.010 K/sec
1 cpu-migrations # 0.001 K/sec
1,316 page-faults # 0.002 M/sec
3,025,639,349 cycles # 4.363 GHz
<not supported> stalled-cycles-frontend
<not supported> stalled-cycles-backend
4,694,848,271 instructions # 1.55 insns per cycle
994,496,704 branches # 1434.037 M/sec
19,693,239 branch-misses # 1.98% of all branches
0.693724345 seconds time elapsed
[fix GH-1147]
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@58904 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2017-05-26 08:12:13 -04:00
compiler . post_cmd = [ eoutvar ]
2002-11-17 11:11:40 -05:00
end
2004-11-25 10:23:19 -05:00
# Generate results and print them. (see ERB#result)
2012-11-09 09:33:11 -05:00
def run ( b = new_toplevel )
2002-11-17 11:11:40 -05:00
print self . result ( b )
end
2004-11-25 10:23:19 -05:00
#
# Executes the generated ERB code to produce a completed template, returning
2012-12-23 02:13:07 -05:00
# the results of that code. (See ERB::new for details on how this process
# can be affected by _safe_level_.)
2009-03-05 22:56:38 -05:00
#
2014-05-29 21:22:23 -04:00
# _b_ accepts a Binding object which is used to set the context of
2004-11-25 10:23:19 -05:00
# code evaluation.
#
2012-11-09 09:33:11 -05:00
def result ( b = new_toplevel )
2019-03-27 23:46:48 -04:00
unless @_init . equal? ( self . class . singleton_class )
raise ArgumentError , " not initialized "
end
2002-11-17 11:11:40 -05:00
if @safe_level
2017-12-28 15:09:24 -05:00
proc do
prev_safe_level = $SAFE
2011-05-18 17:19:18 -04:00
$SAFE = @safe_level
2014-12-12 05:31:47 -05:00
eval ( @src , b , ( @filename || '(erb)' ) , @lineno )
2017-12-28 15:09:24 -05:00
ensure
$SAFE = prev_safe_level
end . call
2002-11-17 11:11:40 -05:00
else
2014-12-12 05:31:47 -05:00
eval ( @src , b , ( @filename || '(erb)' ) , @lineno )
2002-11-17 11:11:40 -05:00
end
end
2017-05-25 11:38:25 -04:00
# Render a template on a new toplevel binding with local variables specified
# by a Hash object.
def result_with_hash ( hash )
2017-12-22 03:08:31 -05:00
b = new_toplevel ( hash . keys )
2017-05-25 11:38:25 -04:00
hash . each_pair do | key , value |
b . local_variable_set ( key , value )
end
result ( b )
end
2013-01-25 22:58:33 -05:00
##
# Returns a new binding each time *near* TOPLEVEL_BINDING for runs that do
# not specify a binding.
2017-12-22 03:08:31 -05:00
def new_toplevel ( vars = nil )
b = TOPLEVEL_BINDING
if vars
vars = vars . select { | v | b . local_variable_defined? ( v ) }
unless vars . empty?
return b . eval ( " tap {|; #{ vars . join ( ',' ) } | break binding} " )
end
end
b . dup
2012-11-09 09:33:11 -05:00
end
private :new_toplevel
2013-07-18 09:50:32 -04:00
# Define _methodname_ as instance method of _mod_ from compiled Ruby source.
2009-01-03 10:36:14 -05:00
#
# example:
# filename = 'example.rhtml' # 'arg1' and 'arg2' are used in example.rhtml
# erb = ERB.new(File.read(filename))
# erb.def_method(MyClass, 'render(arg1, arg2)', filename)
# print MyClass.new.render('foo', 123)
def def_method ( mod , methodname , fname = '(ERB)' )
2016-01-29 00:14:31 -05:00
src = self . src . sub ( / ^(?! # |$) / ) { " def #{ methodname } \n " } << " \n end \n "
2008-12-29 04:26:34 -05:00
mod . module_eval do
2016-01-29 00:14:31 -05:00
eval ( src , binding , fname , - 1 )
2008-12-29 04:26:34 -05:00
end
2002-11-17 11:11:40 -05:00
end
2009-01-03 10:36:14 -05:00
# Create unnamed module, define _methodname_ as instance method of it, and return it.
#
# example:
# filename = 'example.rhtml' # 'arg1' and 'arg2' are used in example.rhtml
# erb = ERB.new(File.read(filename))
# erb.filename = filename
# MyModule = erb.def_module('render(arg1, arg2)')
# class MyClass
# include MyModule
# end
def def_module ( methodname = 'erb' )
2002-11-17 11:11:40 -05:00
mod = Module . new
2009-01-03 10:36:14 -05:00
def_method ( mod , methodname , @filename || '(ERB)' )
2002-11-17 11:11:40 -05:00
mod
end
2009-01-03 10:36:14 -05:00
# Define unnamed class which has _methodname_ as instance method, and return it.
#
# example:
# class MyClass_
# def initialize(arg1, arg2)
# @arg1 = arg1; @arg2 = arg2
# end
# end
# filename = 'example.rhtml' # @arg1 and @arg2 are used in example.rhtml
# erb = ERB.new(File.read(filename))
# erb.filename = filename
# MyClass = erb.def_class(MyClass_, 'render()')
# print MyClass.new('foo', 123).render()
def def_class ( superklass = Object , methodname = 'result' )
2002-11-21 09:39:26 -05:00
cls = Class . new ( superklass )
2009-01-03 10:36:14 -05:00
def_method ( cls , methodname , @filename || '(ERB)' )
2002-11-17 11:11:40 -05:00
cls
end
end
2004-11-25 10:23:19 -05:00
#--
2002-11-17 11:11:40 -05:00
# ERB::Util
class ERB
2004-11-25 10:23:19 -05:00
# A utility module for conversion routines, often handy in HTML generation.
2011-05-24 19:24:32 -04:00
module Util
2002-11-17 11:11:40 -05:00
public
2004-11-25 10:23:19 -05:00
#
# A utility method for escaping HTML tag characters in _s_.
2009-03-05 22:56:38 -05:00
#
2011-05-18 17:19:18 -04:00
# require "erb"
# include ERB::Util
2009-03-05 22:56:38 -05:00
#
2011-05-18 17:19:18 -04:00
# puts html_escape("is a > 0 & a < 10?")
2009-03-05 22:56:38 -05:00
#
2004-11-25 10:23:19 -05:00
# _Generates_
2009-03-05 22:56:38 -05:00
#
2011-05-18 17:19:18 -04:00
# is a > 0 & a < 10?
2004-11-25 10:23:19 -05:00
#
2002-11-17 11:11:40 -05:00
def html_escape ( s )
2012-08-13 22:01:05 -04:00
CGI . escapeHTML ( s . to_s )
2002-11-17 11:11:40 -05:00
end
alias h html_escape
2005-02-12 11:34:45 -05:00
module_function :h
module_function :html_escape
2009-03-05 22:56:38 -05:00
2004-11-25 10:23:19 -05:00
#
# A utility method for encoding the String _s_ as a URL.
2009-03-05 22:56:38 -05:00
#
2011-05-18 17:19:18 -04:00
# require "erb"
# include ERB::Util
2009-03-05 22:56:38 -05:00
#
2011-05-18 17:19:18 -04:00
# puts url_encode("Programming Ruby: The Pragmatic Programmer's Guide")
2009-03-05 22:56:38 -05:00
#
2004-11-25 10:23:19 -05:00
# _Generates_
2009-03-05 22:56:38 -05:00
#
2011-05-18 17:19:18 -04:00
# Programming%20Ruby%3A%20%20The%20Pragmatic%20Programmer%27s%20Guide
2004-11-25 10:23:19 -05:00
#
2002-11-17 11:11:40 -05:00
def url_encode ( s )
2017-05-17 07:58:09 -04:00
s . to_s . b . gsub ( / [^a-zA-Z0-9_ \ -.~] /n ) { | m |
2017-09-29 07:00:00 -04:00
sprintf ( " %%%02X " , m . unpack1 ( " C " ) )
2008-04-30 08:40:52 -04:00
}
2002-11-17 11:11:40 -05:00
end
alias u url_encode
2005-02-12 11:34:45 -05:00
module_function :u
module_function :url_encode
2002-11-17 11:11:40 -05:00
end
end
2004-11-25 10:23:19 -05:00
#--
2002-11-17 11:11:40 -05:00
# ERB::DefMethod
class ERB
2009-01-03 10:36:14 -05:00
# Utility module to define eRuby script as instance method.
#
# === Example
#
# example.rhtml:
# <% for item in @items %>
# <b><%= item %></b>
# <% end %>
#
# example.rb:
# require 'erb'
# class MyClass
# extend ERB::DefMethod
# def_erb_method('render()', 'example.rhtml')
# def initialize(items)
# @items = items
# end
# end
# print MyClass.new([10,20,30]).render()
#
# result:
#
# <b>10</b>
#
# <b>20</b>
#
# <b>30</b>
#
2011-05-24 19:24:32 -04:00
module DefMethod
2002-11-17 11:11:40 -05:00
public
2011-05-24 19:22:40 -04:00
# define _methodname_ as instance method of current module, using ERB
# object or eRuby file
2009-01-03 10:36:14 -05:00
def def_erb_method ( methodname , erb_or_fname )
if erb_or_fname . kind_of? String
fname = erb_or_fname
erb = ERB . new ( File . read ( fname ) )
erb . def_method ( self , methodname , fname )
2003-04-22 12:29:47 -04:00
else
2009-01-03 10:36:14 -05:00
erb = erb_or_fname
erb . def_method ( self , methodname , erb . filename || '(ERB)' )
2002-11-17 11:11:40 -05:00
end
end
module_function :def_erb_method
end
end