Class: Inversion::Template::Tag

Inherits:
Node
  • Object
show all
Extended by:
MethodUtilities, Loggability
Includes:
AbstractClass
Defined in:
lib/inversion/template/tag.rb

Overview

Inversion template tag node base class. Represents a directive in a template that defines behavior and/or state.

This class supports the RubyGems plugin API: to provide one or more Inversion tags in a gem of your own, put them into a directory named ‘inversion/template’ and name the files <tagname>tag.rb and the classes <tagname.capitalize>Tag.

Constant Summary collapse

TAG_PLUGIN_PATTERN =

The glob pattern for matching template tag plugins

'inversion/template/*tag.rb'

Instance Attribute Summary collapse

Attributes inherited from Node

#colnum, #linenum

Class Method Summary collapse

Instance Method Summary collapse

Methods included from MethodUtilities

singleton_attr_accessor, singleton_attr_reader, singleton_attr_writer

Methods included from AbstractClass

included

Methods included from AbstractClass::ClassMethods

#inherited, #pure_virtual

Methods inherited from Node

#after_appending, #after_rendering, #before_appending, #before_rendering, #is_container?, #location, #render

Constructor Details

#initialize(body, linenum = nil, colnum = nil) ⇒ Tag

Create a new Inversion::Template::Tag with the specified ‘body`.



140
141
142
143
# File 'lib/inversion/template/tag.rb', line 140

def initialize( body, linenum=nil, colnum=nil )
	super
	@body = body.to_s.strip
end

Instance Attribute Details

#bodyObject (readonly)

the body of the tag



151
152
153
# File 'lib/inversion/template/tag.rb', line 151

def body
  @body
end

Class Method Details

.create(tagname, body, linenum = nil, colnum = nil) ⇒ Object

Create a new Inversion::Template::Tag from the specified ‘tagname` and `body`.



121
122
123
124
125
126
127
128
129
130
131
132
# File 'lib/inversion/template/tag.rb', line 121

def self::create( tagname, body, linenum=nil, colnum=nil )
	tagname =~ /^(\w+)$/i or raise ArgumentError, "invalid tag name %p" % [ tagname ]
	tagtype = $1.downcase

	unless tagclass = self.types[ tagtype.to_sym ]
		Inversion.log.warn "Unknown tag type %p; registered: %p" %
			[ tagtype, self.types.keys ]
		return nil
	end

	return tagclass.new( body, linenum, colnum )
end

.inherited(subclass) ⇒ Object

Inheritance hook – keep track of loaded derivatives.



48
49
50
51
52
53
# File 'lib/inversion/template/tag.rb', line 48

def self::inherited( subclass )
	# Inversion.log.debug "%p inherited from %p" % [ subclass, self ]
	Inversion::Template::Tag.derivatives << subclass
	Inversion.log.debug "Loaded tag type %p" % [ subclass ]
	super
end

.load(tagfile) ⇒ Object

Safely load the specified ‘tagfile`.



108
109
110
111
112
113
114
115
116
117
# File 'lib/inversion/template/tag.rb', line 108

def self::load( tagfile )
	tagrequire = tagfile[ %r{inversion/template/\w+tag} ] or
		raise "tag file %p doesn't look like a tag plugin" % [ tagfile ]
	require( tagrequire )
rescue => err
	Inversion.log.error "%s while loading tag plugin %p: %s" %
		[ err.class.name, tagfile, err.message ]
	Inversion.log.debug "  " + err.backtrace.join( "\n  " )
	return false
end

.load_allObject

Load all available template tags and return them as a Hash keyed by their name.



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
# File 'lib/inversion/template/tag.rb', line 64

def self::load_all
	tags = {}

	Gem.find_files( TAG_PLUGIN_PATTERN ).each do |tagfile|
		tagname = tagfile[ %r{/(\w+?)_?tag\.rb$}, 1 ]
		next unless tagname

		self.load( tagfile )

		# Inversion.log.debug "Looking for class for %p tag" % [ tagname ]
		tagclass = self.derivatives.find do |derivclass|
			if derivclass.name.nil? || derivclass.name.empty?
				# Inversion.log.debug "  skipping anonymous class %p" % [ derivclass ]
				nil
			elsif !derivclass.respond_to?( :new )
				# Inversion.log.debug "  skipping abstract class %p" % [ derivclass ]
				nil
			else
				derivclass.name.downcase =~ /\b#{tagname.gsub('_', '')}tag$/
			end
		end

		unless tagclass
			Inversion.log.debug "  no class found for %p tag" % [ tagname ]
			next
		end

		Inversion.log.debug "  found: %p" % [ tagclass ]
		snakecase_name = tagclass.name.sub( /^.*\b(\w+)Tag$/i, '\1' )
		snakecase_name = snakecase_name.gsub( /([a-z])([A-Z])/, '\1_\2' ).downcase
		Inversion.log.debug "  mapping %p to names: %p"  % [ tagclass, snakecase_name ]

		tags[ snakecase_name.to_sym ] = tagclass
		tags[ snakecase_name.gsub('_', '').to_sym ] = tagclass
	end

	@types ||= {}
	@types.merge!( tags )

	return @types
end

.typesObject

Return a Hash of all loaded tag types, loading them if they haven’t been loaded already.



57
58
59
60
# File 'lib/inversion/template/tag.rb', line 57

def self::types
       self.load_all unless @types
       return @types
end

Instance Method Details

#as_comment_bodyObject

Render the tag as the body of a comment, suitable for template debugging.



155
156
157
# File 'lib/inversion/template/tag.rb', line 155

def as_comment_body
	return "%s %s at %s" % [ self.tagname, self.body.to_s.dump, self.location ]
end

#derivativesObject

The Array of subclasses of this class



44
# File 'lib/inversion/template/tag.rb', line 44

singleton_attr_reader :derivatives

#tagnameObject

Return the human-readable name of the tag class



161
162
163
# File 'lib/inversion/template/tag.rb', line 161

def tagname
	return self.class.name.sub(/Tag$/, '').sub( /^.*::/, '' )
end

#typesObject

The hash of loaded tag types, keyed by the tag name as a Symbol



40
# File 'lib/inversion/template/tag.rb', line 40

singleton_attr_reader :types