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.



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

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

Instance Attribute Details

#bodyObject (readonly)

the body of the tag



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

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.



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

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.



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

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.



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

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.



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

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.



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

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.



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

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



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

singleton_attr_reader :derivatives

#tagnameObject

Return the human-readable name of the tag class



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

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



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

singleton_attr_reader :types