class Webgen::Tag
Namespace for all webgen tags.
About¶ ↑
A tag object is a webgen extension that handles specific webgen tags. webgen tags are used to add dynamic content to page and template files (or any other file for that matter) and are made for ease of use.
Implementing a tag¶ ↑
A tag object only needs to respond to the method call
which needs to accept three parameters:
- tag
-
The name of the tag which should be processed (useful for tag objects which can process different tags).
- body
-
Holds the body value for the tag if any.
- context
-
Holds all relevant information for processing – have a look at the
Webgen::Context
class to see what is available. The special key :config is set to anWebgen::Configuration
object that should be used to retrieve configuration option values because the values might be changed due to options set directly via the tag syntax.
The method has to return the result of the processing and, optionally, a boolean value specifying if the result should further be processed (ie. webgen tags replaced).
This allows one to implement a tag object as a class with a class method called call
. Or as a Proc object.
The tag object has to be registered so that webgen knows about it, see register
for more information.
Tag
options¶ ↑
webgen tags allow the specification of options in the tag definition. When registering a tag, one can specify which options are mandatory, i.e. which options always have to be set directly for the tag. The value of the option :config_prefix for the register
method is used to resolve partially stated configuration entries.
Sample Tag
¶ ↑
Following is a simple tag class example which just reverses the body text and adds some information about the context to the result.
Put the following into the ext/init.rb file of your webgen website:
class Reverser def self.call(tag, body, context) result = context[:config]['tag.reverser.do_reverse'] ? body.reverse : body result << "\nNode: " << context.content_node.alcn << " (" << context.content_node['title'] << ")" result << "\nReference node: " << context.ref_node.alcn result end end website.config.define_option('tag.reverser.do_reverse', nil) website.ext.tag.register(Reverser, :names => 'reverse', :config_prefix => 'tag.reverser', :mandatory => ['do_reverse'])
Then you can use the reverser tag as follows in a page file:
{reverse:: {do_reverse: true}}This text is reversed{reverse}
Public Class Methods
Render the tag template for the given tag and return the result.
The value of the configuration option 'tag.<TAG>.template' (where '<TAG>' is replaced with tag
) is used as template path.
If the template node cannot be found, an empty string is returned.
# File lib/webgen/tag.rb 84 def self.render_tag_template(context, tag) 85 path = context[:config]["tag.#{tag}.template"] 86 if path && template_node = context.ref_node.resolve(path, context.dest_node.lang, true) 87 context.website.ext.item_tracker.add(context.dest_node, :template_chain, template_node) 88 context.render_block(:name => "tag.#{tag}", :node => 'first', 89 :chain => [*template_node.template_chain, template_node, context.content_node]) 90 else 91 context.website.logger.warn { "Template node '#{path}' for tag '#{tag}' not found" } 92 '' 93 end 94 end
Public Instance Methods
Process the tag
and return the result.
The parameter params
(can be a Hash
, a String or nil) needs to contain the parameters for the tag and body
is the optional body for the tag. context
needs to be a valid Webgen::Context
object.
# File lib/webgen/tag.rb 164 def call(tag, params, body, context) 165 result = '' 166 tdata = tag_data(tag, context) 167 if !tdata.nil? 168 context = context.clone(:config => create_config(tag, params, tdata, context)) 169 result, process_output = tdata.object.call(tag, body, context) 170 if process_output 171 context.content = result 172 result = context.website.ext.content_processor.call('tags', context).content 173 end 174 else 175 raise Webgen::RenderError.new("No tag processor for '#{tag}' found", 'tag', 176 context.dest_node, context.ref_node) 177 end 178 result 179 rescue Webgen::Error => e 180 e.path = context.dest_node if e.path.to_s.empty? 181 e.location = "tag.#{tag}" unless e.location 182 raise 183 rescue Exception => e 184 raise Webgen::RenderError.new(e, "tag.#{tag}", context.dest_node, context.ref_node) 185 end
Register a tag.
The parameter klass
can either be a String containing the name of a class/module (which has to respond to :call) or an object that responds to :call. If the class is located under this namespace, only the class name without the hierarchy part is needed, otherwise the full class/module name including parent module/class names is needed.
Instead of registering an object that responds to :call, you can also provide a block that processes a tag.
Options:¶ ↑
- :names
-
The tag name or an array of tag names. If not set, it defaults to the lowercase version of the class name (without the hierarchy part).
The name :default is used for specifying the default tag which is called if an unknown tag name is encountered.
- :config_prefix
-
The configuration prefix, i.e. the part of a configuration option name that does not need to be specified. Defaults to the full class name without the
Webgen
module downcased and all “::” substituted with “.” (e.g.Webgen::Tag::Menu
→ tag.menu). Needs to be specified when a block is used! - :mandatory
-
A list of configuration option names whose values always need to be provided. The first configuration option name is used as the default mandatory option (used when only a string is provided in the tag definition).
Examples:¶ ↑
tag.register('Date') # registers Webgen::Tag::Date tag.register('::Date') # registers Date !!! tag.register('MyModule::Date', names: ['mydate', 'date']) tag.register('date', config_prefix: 'tag.date') do |tag, body, context| Time.now.strftime(param('tag.date.format')) end
# File lib/webgen/tag.rb 144 def register(klass, options = {}, &block) 145 if block_given? && !options[:config_prefix] 146 raise ArgumentError, "The option :config_prefix needs to be specified when registering a tag using a block" 147 end 148 149 names = [options.delete(:names)].flatten.compact 150 options[:name] = names.shift 151 name = do_register(klass, options, true, &block) 152 ext_data(name).mandatory = options[:mandatory] || [] 153 ext_data(name).config_prefix = options[:config_prefix] || 154 Webgen::Utils.snake_case(ext_data(name).object.to_s.gsub(/::/, '.').gsub(/^Webgen\./, '')) 155 ext_data(name).initialized = false 156 names.each {|n| @extensions[n.to_sym] = @extensions[name]} 157 end
Private Instance Methods
Create the Webgen::Configuration
object from the parameters and the given configuration prefix.
# File lib/webgen/tag.rb 198 def create_config(tag, params, tdata, context) 199 values = case params 200 when Hash 201 values_from_hash(tag, params, tdata, context) 202 when String, Array, TrueClass, FalseClass, Numeric 203 values_for_default_mandatory(tag, params, tdata, context) 204 when NilClass then {} 205 else 206 raise Webgen::RenderError.new("Invalid parameter type (#{params.class})", 207 "tag", context.dest_node, context.ref_node) 208 end 209 210 if !tdata.mandatory.all? {|k| values.has_key?(k)} 211 raise Webgen::RenderError.new("Not all mandatory parameters set", "tag", context.dest_node, context.ref_node) 212 end 213 config = context.website.config.dup 214 config.set_values(values) 215 config.freeze 216 config 217 end
Return the tag data for tag
or nil
if tag
is unknown.
# File lib/webgen/tag.rb 252 def tag_data(tag, context) 253 tdata = @extensions[tag.to_sym] || @extensions[:default] 254 if tdata && !tdata.initialized 255 tdata.object = resolve_class(tdata.object) 256 tdata.mandatory.each_with_index do |o, index| 257 next if context.website.config.option?(o) 258 o = tdata.config_prefix + '.' + o 259 if context.website.config.option?(o) 260 tdata.mandatory[index] = o 261 else 262 raise ArgumentError, "Invalid configuration option name '#{o}' specified as mandatory option for tag '#{tag}'" 263 end 264 end 265 tdata.initialized = true 266 end 267 tdata 268 end
Return a hash containing valid configuration options by setting the default mandatory parameter for tag
to value
.
# File lib/webgen/tag.rb 239 def values_for_default_mandatory(tag, value, tdata, context) 240 if tdata.mandatory.first.nil? 241 context.website.logger.error do 242 ["No default mandatory option specified for tag '#{tag}' but set in <#{context.ref_node}>", 243 "Use the {key: value} syntax for assigning the value '#{value}' to the intended tag option!"] 244 end 245 {} 246 else 247 {tdata.mandatory.first => value} 248 end 249 end
Return a hash containing valid configuration options by taking key-value pairs from params
.
# File lib/webgen/tag.rb 220 def values_from_hash(tag, params, tdata, context) 221 result = {} 222 params.each do |key, value| 223 if context.website.config.option?(key) 224 result[key] = value 225 elsif context.website.config.option?(tdata.config_prefix + '.' + key) 226 result[tdata.config_prefix + '.' + key] = value 227 else 228 context.website.logger.warn do 229 ["Invalid configuration option '#{key}' for tag '#{tag}' found in <#{context.ref_node}>", 230 "Remove the invalid key '#{key}' to fix the warning."] 231 end 232 end 233 end 234 result 235 end