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