lib/html/template/pro.rb in html-template-pro-0.0.2 vs lib/html/template/pro.rb in html-template-pro-0.0.3

- old
+ new

@@ -1,37 +1,47 @@ +# -*- coding: utf-8 -*- require 'html/template/internal' -module HTML - module Template +module HTML # :nodoc: + module Template # :nodoc: - def Internal.register_functions_impl(registory, func_spec, &block) - if block && func_spec.kind_of?(Symbol) - registory[func_spec] = block - elsif func_spec.kind_of? Hash - unless func_spec.values.all?{|e| e.kind_of? Proc} - raise ArgumentError, "functions must be kind_of Proc" + module Internal # :nodoc: + + class State # :nodoc: + # supress documentation + end + + module_function + + def register_functions_impl(registory, func_spec, &block) # :nodoc: + if block && func_spec.kind_of?(Symbol) + registory[func_spec] = block + elsif func_spec.kind_of? Hash + unless func_spec.values.all?{|e| e.kind_of? Proc} + raise ArgumentError, "functions must be kind_of Proc" + end + registory.update(func_spec) + else + raise ArgumentError, "first argument must be symbol or hash contains functions" end - registory.update(func_spec) - else - raise ArgumentError, "first argument must be symbol or hash contains functions" end end class Pro - VERSION = "0.0.2" + VERSION = "0.0.3" - include HTML::Template::Internal - - INPUTS = [:filename, :filehandle, :arrayref, :scalarref, :source] - + # :stopdoc: ASK_NAME_DEFAULT = 0 ASK_NAME_AS_IS = 1 ASK_NAME_LOWERCASE = 2 ASK_NAME_UPPERCASE = 4 ASK_NAME_MASK = ASK_NAME_AS_IS | ASK_NAME_LOWERCASE | ASK_NAME_UPPERCASE + INPUTS = [:filename, :filehandle, :arrayref, :scalarref, :source] + # :startdoc: + @@func = { # note that length,defined,sin,cos,log,tan,... are built-in :sprintf => lambda { |*args| sprintf(*args) }, :substr => lambda { |str, *args| args.size == 2 ? str[*args] : str[args[0]..-1] }, :lc => lambda { |str| str.downcase }, @@ -45,10 +55,146 @@ # :oct => lambda { |obj| obj.to_s.oct }, :rand => lambda { |num| rand num }, :srand => lambda { |seed| srand seed }, } + # Create a `Template' object. `Template' source is specified by several way. + # Exactly one kind of source must be specified. + # + # * specify filename + # + # template = HTML::Template::Pro.new(:filename => 'foo.tmpl') + # + # * specify source as string + # + # template = HTLM::Template::Pro.new(:source => '<html><body><TMPL_VAR NAME="hello">!!</body></html>') + # + # * specify source by array of string + # + # template = HTLM::Template::Pro.new(:source => ['<html>', '<body><TMPL_VAR NAME="hello">!!</body>', '</html>']) + # + # * specify IO object + # + # template = HTLM::Template::Pro.new(:source => $stdin) + # + # === Other options + # + # ==== path + # + # Array of file path which include template files. + # + # Example: + # + # # find out tmpl/foo.tmpl + # template = HTLM::Template::Pro.new(:filename => 'foo.tmpl', :path => ['tmpl']) + # + # ==== search_path_on_include + # + # Boolean that indicates whether we search directory specified + # by `path' param when we meet the TMPL_INCLUDE tag. + # + # Example: + # + # # tmpl_includes/foo.tmpl is used. + # template = HTLM::Template::Pro.new(:source => '<TMPL_INCLUDE NAME="foo.tmpl">', + # :path => ['tmpl_includes'], + # :search_path_on_include => true) + # + # ==== associate + # + # this option allows you to inherit the parameter values from + # other objects. The only requirement for the other object is + # that it have a "param()" method that works like HTML::Template::Pro#param. + # + # ==== case_sensitive + # + # if this options is true, template variable is treated as case sensitive. + # + # Example: + # + # template = HTML::Template::Pro.new(:source => '<TMPL_VAR NAME="FoO">', + # :case_sensitive => true) + # template.param(:foo => 100) + # puts template.output # output empty string ( foo is not 'FoO' ) + # + # ==== loop_context_vars + # + # when this parameter is set to true (it is false by default) + # five loop context variables are made available inside a loop: + # __first__, __last__, __inner__, __odd__, __counter__. They + # can be used with <TMPL_IF>, <TMPL_UNLESS> and <TMPL_ELSE> to + # control how a loop is output. + # + # Example: + # In your templates, + # + # <TMPL_LOOP NAME="loop"> + # <TMPL_IF NAME="__first__">First!</TMPL_IF> + # <TMPL_VAR NAME="__counter__"> + # <TMPL_IF NAME="__last__">Last!</TMPL_IF> + # </TMPL_LOOP> + # + # ==== no_includes + # + # set this option to true to disallow the <TMPL_INCLUDE> tag in the + # template file. This can be used to make opening untrusted + # templates *slightly* less dangerous. Defaults to false. + # + # ==== max_includes + # + # set this variable to determine the maximum depth that includes + # can reach. Set to 10 by default. Including files to a depth + # greater than this value causes an error message to be + # displayed. Set to 0 to disable this protection. + # + # ==== global_vars + # + # normally variables declared outside a loop are not available + # inside a loop. This option makes <TMPL_VAR>s like global + # variables - they have unlimited scope. This option also + # affects <TMPL_IF> and <TMPL_UNLESS>. + # + # ==== path_like_variable_scope + # + # this option switches on a Shigeki Morimoto extension to + # HTML::Template::Pro that allows access to variables that are + # outside the current loop scope using path-like expressions. + # + # Example: + # + # <TMPL_LOOP NAME=class> + # <TMPL_LOOP NAME=person> + # <TMPL_VAR NAME="../teacher_name"> <!-- access to class.teacher_name --> + # <TMPL_VAR NAME="name"> + # <TMPL_VAR NAME="/top_level_value"> <!-- access to top level value --> + # <TMPL_VAR NAME="age"> + # <TMPL_LOOP NAME="../../school"> <!-- enter loop before accessing its vars --> + # <TMPL_VAR NAME="school_name"> <!-- access to [../../]school.school_name --> + # </TMPL_LOOP> + # </TMPL_LOOP> + # </TMPL_LOOP> + # + # ==== filter + # + # By using this option, you can filter the source of template + # before HTML::Template::Pro prcesses it. + # + # Example: + # + # myfilter = ->(source){ source.gsub(/Foo/, 'Bar') } + # template = HTML::Template::Pro.new(:source => '<TMPL_VAR NAME="Foo">!!', + # :filter => myfilter) + # template.param(:Bar => 'hello') + # puts template.output # displays 'hello!!' + # + # ==== default_escape + # + # Set this parameter to "HTML", "URL" or "JS" and + # HTML::Template::Pro will apply the specified escaping to all + # variables unless they declare a different escape in the + # template. + # def initialize(args={}) @options = default_options.merge(args) if args.keys.count(&INPUTS.method(:include?)) != 1 raise ArgumentError, "HTML::Template::Pro.new called with multiple (or no) template sources specified!" end @@ -64,10 +210,52 @@ @scalarref = call_filters @scalarref end @filtered_template = {} end + # #param can be called in a number of ways. + # + # 1. call with no arguments. + # + # returns a list of parameters set after new. + # + # Example: + # template = HTML::Template::Pro.new(:filename => 'foo.tmpl') + # template.param(:foo => 10, :bar => 20) + # params = template.param # returns [:foo, :bar] + # + # 2. pass one parameter name. + # + # returns the value of a parameter. + # + # Example: + # template = HTML::Template::Pro.new(:filename => 'foo.tmpl') + # template.param(:foo => 10, :bar => 20) + # val = template.param(:foo) # now `val' equals 10. + # + # 3. pass hash. + # + # assign values to parameters. + # + # Example: + # + # template = HTML::Template::Pro.new(:source => <<'TMPL') + # <TMPL_VAR NAME="foo"> + # <TMPL_VAR NAME="bar"> + # TMPL + # template.param(:foo => 10, :bar => 20) + # puts template.output # displays "10\n20\n" + # + # # you can specify the value by passing block. + # # in this way, you must assign exactly one parameter. + # template.param(:foo) { Time.now } + # puts template.output # prints the time #output is executed. + # + # # Or you can use proc or lambda. + # template.param(:foo => lambda { Time.now }, + # :bar => lambda { rand(100) }) + # def param(args=nil, &block) return @params.keys if args.nil? if !(args.kind_of? Hash) key = @options[:case_sensitive] ? args : args.downcase if block @@ -77,38 +265,97 @@ end end merge_params(args) end + # Clear the internal param hash. All the parameters set before + # this call is reset. def clear_params @params.clear end + # returns the final result of the template. If you want to print + # out the result, you can do: + # puts template.output + # + # When `output' is called each occurrence of <TMPL_VAR + # NAME=name> is replaced with the value assigned to "name" via + # "param()". If a named parameter is unset it is simply replaced + # with ’’. <TMPL_LOOPS> are evaluated once per parameter set, + # accumulating output on each pass. + # + # You may optionally supply a IO object to print: + # File.open('result.html', 'w') do |file| + # template.output(:print_to => file) + # end def output(options={}) @options[:associate].reverse.each do |assoc| assoc.param.each do |key| param(key => assoc.param(key)) unless @params[key] end end if (options.include? :print_to) - exec_tmpl(options[:print_to]) + HTML::Template::Internal.exec_tmpl(self, options[:print_to]) else output_string = String.new - exec_tmpl(output_string) + HTML::Template::Internal.exec_tmpl(self, output_string) return output_string end end + # <b>for perl compatibility</b> + # + # shortcut to HTML::Template::Pro.new(:filehandle => file) def self.new_filehandle(file) self.new(:filehandle => file) end + # <b>for perl compatibility</b> + # + # shortcut to HTML::Template::Pro.new(:filename => filename) + def self.new_file(filename) + self.new(:filename => file) + end + + # <b>for perl compatibility</b> + # + # shortcut to HTML::Template::Pro.new(:arrayref => lines) + def self.new_array_ref(lines) + self.new(:arrayref => lines) + end + + # <b>for perl compatibility</b> + # + # shortcut to HTML::Template::Pro.new(:scalarref => source_string) + def self.new_scalar_ref(source) + self.new(:scalarref => source) + end + + # register the function globally. See HTML::Template::Pro#register_function. + # Functions registered by this class method is shared by all instances. def self.register_function(func_spec, &block) HTML::Template::Internal.register_functions_impl(@@func, func_spec, &block) end + # define a new function that can be used in <tt><TMPL_VAR + # EXPR=""></tt> tag. function is specified by block or lambda. + # + # Example: + # template = HTML::Template::Pro.new(:source => '<TMPL_VAR EXPR="double(10)">') + # template.register_function(:double) {|num| num * 2 } + # # or template.register_function(:double => lambda {|num| num * 2 }) + # puts template.output # displays `20' + # + # You can also register the functions by passing lambdas to new. + # + # Example: + # template = HTML::Template::Pro.new(:filename => 'foo.tmpl', + # :functions => { + # :square => lambda {|x| x * x }, + # }) + # def register_function(func_spec, &block) HTML::Template::Internal.register_functions_impl(@options[:expr_func], func_spec, &block) end private