inversion 0.1.1 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (43) hide show
  1. data.tar.gz.sig +0 -0
  2. data/ChangeLog +157 -28
  3. data/History.rdoc +8 -0
  4. data/Manifest.txt +2 -3
  5. data/Rakefile +1 -3
  6. data/lib/inversion.rb +2 -2
  7. data/lib/inversion/exceptions.rb +1 -1
  8. data/lib/inversion/{template/parser.rb → parser.rb} +5 -5
  9. data/lib/inversion/renderstate.rb +55 -5
  10. data/lib/inversion/template.rb +5 -3
  11. data/lib/inversion/template/attrtag.rb +19 -12
  12. data/lib/inversion/template/begintag.rb +1 -2
  13. data/lib/inversion/template/configtag.rb +7 -1
  14. data/lib/inversion/template/containertag.rb +8 -3
  15. data/lib/inversion/template/elsetag.rb +16 -0
  16. data/lib/inversion/template/elsiftag.rb +16 -0
  17. data/lib/inversion/template/escapetag.rb +1 -1
  18. data/lib/inversion/template/fortag.rb +2 -5
  19. data/lib/inversion/template/iftag.rb +17 -35
  20. data/lib/inversion/template/importtag.rb +2 -1
  21. data/lib/inversion/template/includetag.rb +2 -0
  22. data/lib/inversion/template/node.rb +1 -1
  23. data/lib/inversion/template/tag.rb +5 -2
  24. data/lib/inversion/template/textnode.rb +1 -2
  25. data/lib/inversion/template/unlesstag.rb +16 -26
  26. data/lib/inversion/template/yieldtag.rb +3 -8
  27. data/spec/inversion/{template/parser_spec.rb → parser_spec.rb} +14 -14
  28. data/spec/inversion/renderstate_spec.rb +242 -165
  29. data/spec/inversion/template/attrtag_spec.rb +10 -18
  30. data/spec/inversion/template/begintag_spec.rb +13 -12
  31. data/spec/inversion/template/configtag_spec.rb +5 -7
  32. data/spec/inversion/template/elsetag_spec.rb +5 -5
  33. data/spec/inversion/template/elsiftag_spec.rb +5 -5
  34. data/spec/inversion/template/endtag_spec.rb +1 -1
  35. data/spec/inversion/template/fortag_spec.rb +22 -1
  36. data/spec/inversion/template/iftag_spec.rb +14 -0
  37. data/spec/inversion/template/rescuetag_spec.rb +4 -4
  38. data/spec/inversion/template/tag_spec.rb +6 -4
  39. data/spec/inversion/template/unlesstag_spec.rb +12 -6
  40. data/spec/inversion/template/yieldtag_spec.rb +2 -2
  41. metadata +31 -32
  42. metadata.gz.sig +0 -0
  43. data/lib/inversion/template/conditionaltag.rb +0 -49
@@ -27,11 +27,13 @@ class Inversion::Template
27
27
 
28
28
 
29
29
  # Load subordinate classes
30
- require 'inversion/template/parser'
30
+ require 'inversion/parser'
31
31
  require 'inversion/template/node'
32
32
  require 'inversion/template/tag'
33
33
  require 'inversion/renderstate'
34
34
 
35
+ # Alias to maintain backward compatibility with <0.2.0 code
36
+ Parser = Inversion::Parser
35
37
 
36
38
  # Valid actions for 'on_render_error'
37
39
  VALID_ERROR_ACTIONS = [
@@ -116,7 +118,7 @@ class Inversion::Template
116
118
  end
117
119
 
118
120
  @source = source
119
- @parser = Inversion::Template::Parser.new( self, opts )
121
+ @parser = Inversion::Parser.new( self, opts )
120
122
  @node_tree = [] # Parser expects this to always be an Array
121
123
  @init_options = opts
122
124
  @options = nil
@@ -176,7 +178,7 @@ class Inversion::Template
176
178
  # Pre-render hook
177
179
  self.walk_tree {|node| node.before_rendering(state) }
178
180
 
179
- self.log.debug " rendering node tree: %p" % [ @node_tree ]
181
+ # self.log.debug " rendering node tree: %p" % [ @node_tree ]
180
182
  self.walk_tree {|node| state << node }
181
183
 
182
184
  # Post-render hook
@@ -77,12 +77,26 @@ class Inversion::Template::AttrTag < Inversion::Template::CodeTag
77
77
  attr_accessor :methodchain
78
78
 
79
79
 
80
- ### Render the tag attributes of the specified +render_state+ and return them.
81
- def render( render_state )
82
- self.log.debug "Rendering %p with state: %p" % [ self, render_state ]
80
+ ### Render the tag attributes of the specified +renderstate+ and return them.
81
+ def render( renderstate )
82
+ self.log.debug "Rendering %p with state: %p" % [ self, renderstate ]
83
83
 
84
+ # Evaluate the tag body and return either false value
85
+ value = self.evaluate( renderstate ) or return value
86
+
87
+ # Apply the format if there is one
88
+ if self.format
89
+ return self.format % value
90
+ else
91
+ return value
92
+ end
93
+ end
94
+
95
+
96
+ ### Evaluate the body of the tag in the context of +renderstate+ and return the results.
97
+ def evaluate( renderstate )
84
98
  value = nil
85
- attribute = render_state.attributes[ self.name.to_sym ]
99
+ attribute = renderstate.attributes[ self.name.to_sym ]
86
100
  self.log.debug " initial attribute: %p" % [ attribute ]
87
101
 
88
102
  # Evaluate the method chain (if there is one) against the attribute
@@ -95,14 +109,7 @@ class Inversion::Template::AttrTag < Inversion::Template::CodeTag
95
109
  end
96
110
  self.log.debug " evaluated value: %p" % [ value ]
97
111
 
98
- return value unless value
99
-
100
- # Apply the format if there is one
101
- if self.format
102
- return self.format % value
103
- else
104
- return value
105
- end
112
+ return value
106
113
  end
107
114
 
108
115
 
@@ -4,7 +4,6 @@
4
4
  require 'inversion/mixins'
5
5
  require 'inversion/template/attrtag'
6
6
  require 'inversion/template/containertag'
7
- require 'inversion/template/conditionaltag'
8
7
  require 'inversion/template/rescuetag'
9
8
 
10
9
 
@@ -85,7 +84,7 @@ class Inversion::Template::BeginTag < Inversion::Template::Tag
85
84
  state.with_destination( output ) do
86
85
  state.with_error_handler( errhandler ) do
87
86
  catch( :stop_rendering ) do
88
- self.render_subnodes( state )
87
+ super
89
88
  end
90
89
  self.log.debug " leaving the error-handler block"
91
90
  end
@@ -51,10 +51,16 @@ class Inversion::Template::ConfigTag < Inversion::Template::Tag
51
51
 
52
52
 
53
53
  ### Override the options in the +parsestate+ when the config is appended to
54
- ### tree.
54
+ ### the tree.
55
55
  def before_appending( parsestate )
56
56
  parsestate.options.merge!( self.options )
57
57
  end
58
58
 
59
+
60
+ ### Override the options in the +renderstate+ when the config is rendered.
61
+ def before_rendering( renderstate )
62
+ renderstate.options.merge!( self.options )
63
+ end
64
+
59
65
  end # class Inversion::Template::ConfigTag
60
66
 
@@ -33,11 +33,16 @@ module Inversion::Template::ContainerTag
33
33
  alias_method :container?, :is_container?
34
34
 
35
35
 
36
+ ### Default render method for containertags; rendering each of its subnodes and
37
+ ### don't render anything for the container itself.
38
+ def render( renderstate )
39
+ self.render_subnodes( renderstate )
40
+ end
41
+
42
+
36
43
  ### Append the container's subnodes to the +renderstate+.
37
44
  def render_subnodes( renderstate )
38
- self.subnodes.each do |node|
39
- renderstate << node
40
- end
45
+ self.subnodes.each {|node| renderstate << node }
41
46
  end
42
47
 
43
48
  end # module Inversion::Template::ContainerTag
@@ -58,5 +58,21 @@ class Inversion::Template::ElseTag < Inversion::Template::Tag
58
58
  raise Inversion::ParseError, "orphaned '%s' tag" % [ self.tagname.downcase ] unless condtag
59
59
  end
60
60
 
61
+
62
+ ### Toggle rendering for the iftag's container if rendering hasn't yet been
63
+ ### toggled.
64
+ def render( renderstate )
65
+ if renderstate.tag_data[ :rendering_was_enabled ]
66
+ self.log.debug " rendering was previously enabled: disabling"
67
+ renderstate.disable_rendering
68
+ else
69
+ self.log.debug " rendering was previously disabled: enabling"
70
+ renderstate.tag_data[ :rendering_was_enabled ] = true
71
+ renderstate.enable_rendering
72
+ end
73
+
74
+ return nil
75
+ end
76
+
61
77
  end # class Inversion::Template::ElseTag
62
78
 
@@ -45,5 +45,21 @@ class Inversion::Template::ElsifTag < Inversion::Template::AttrTag
45
45
  end
46
46
  end
47
47
 
48
+
49
+ ### Toggle rendering for the iftag's container if rendering hasn't yet been
50
+ ### toggled.
51
+ def render( renderstate )
52
+ if renderstate.tag_data[ :rendering_was_enabled ]
53
+ self.log.debug "Rendering was previously enabled; disabling"
54
+ renderstate.disable_rendering
55
+ elsif self.evaluate( renderstate )
56
+ self.log.debug "Rendering was previously disabled, and condition is true; enabling"
57
+ renderstate.tag_data[ :rendering_was_enabled ] = true
58
+ renderstate.enable_rendering
59
+ end
60
+
61
+ return nil
62
+ end
63
+
48
64
  end # class Inversion::Template::ElsifTag
49
65
 
@@ -19,7 +19,7 @@ class Inversion::Template::EscapeTag < Inversion::Template::AttrTag
19
19
  ### Render the method chains against the attributes of the specified +render_state+
20
20
  ### and return them.
21
21
  def render( render_state )
22
- result = self.escape( super, render_state )
22
+ return self.escape( super, render_state )
23
23
  end
24
24
 
25
25
  end # class Inversion::Template::EscapeTag
@@ -82,7 +82,6 @@ class Inversion::Template::ForTag < Inversion::Template::CodeTag
82
82
  ### Iterate over the enumerator in +state+ and render the tag's
83
83
  ### contents for each iteration.
84
84
  def render( state )
85
- result = []
86
85
  lvalue = state.eval( self.enumerator ) or return nil
87
86
 
88
87
  self.log.debug "Rendering %p via block args: %p" % [ lvalue, self.block_args ]
@@ -95,13 +94,11 @@ class Inversion::Template::ForTag < Inversion::Template::CodeTag
95
94
  # Overlay the block args from the 'for' over the template attributes and render
96
95
  # each subnode
97
96
  state.with_attributes( overrides ) do
98
- self.subnodes.each do |node|
99
- result << node.render( state )
100
- end
97
+ super
101
98
  end
102
99
  end
103
100
 
104
- return result.join
101
+ return nil
105
102
  end
106
103
 
107
104
 
@@ -4,7 +4,6 @@
4
4
  require 'inversion/mixins'
5
5
  require 'inversion/template/attrtag'
6
6
  require 'inversion/template/containertag'
7
- require 'inversion/template/conditionaltag'
8
7
  require 'inversion/template/elsiftag'
9
8
  require 'inversion/template/elsetag'
10
9
 
@@ -20,50 +19,33 @@ require 'inversion/template/elsetag'
20
19
  #
21
20
  class Inversion::Template::IfTag < Inversion::Template::AttrTag
22
21
  include Inversion::Loggable,
23
- Inversion::Template::ContainerTag,
24
- Inversion::Template::ConditionalTag
22
+ Inversion::Template::ContainerTag
25
23
 
26
24
  # Inherits AttrTag's tag patterns
27
25
 
28
26
  ### Render the tag's contents if the condition is true, or any else or elsif sections
29
27
  ### if the condition isn't true.
30
28
  def render( state )
31
- self.enable_rendering if super
32
- self.render_subnodes( state )
33
- return nil
34
- end
35
-
36
-
37
- ### Render the tag's subnodes according to the tag's logical state.
38
- def render_subnodes( renderstate )
39
- self.log.debug "Rendering subnodes. Rendering initially %s" %
40
- [ self.rendering_enabled? ? "enabled" : "disabled" ]
41
-
42
- # walk the subtree, modifying the logic flags for else and elsif tags,
43
- # and rendering nodes if rendering is enabled
44
- self.subnodes.each do |node|
45
- case node
46
- when Inversion::Template::ElsifTag
47
- self.log.debug " logic switch: %p..." % [ node ]
48
- if !self.rendering_was_enabled? && node.render( renderstate )
49
- self.enable_rendering
50
- else
51
- self.disable_rendering
52
- end
53
29
 
54
- when Inversion::Template::ElseTag
55
- self.log.debug " logic switch: %p..." % [ node ]
56
- if !self.rendering_was_enabled?
57
- self.enable_rendering
58
- else
59
- self.disable_rendering
60
- end
30
+ # Start out with rendering enabled if the tag body evaluates trueishly
31
+ if self.evaluate( state )
32
+ self.log.debug "Initial state was TRUE; enabling rendering"
33
+ state.enable_rendering
34
+ else
35
+ self.log.debug "Initial state was FALSE; disabling rendering"
36
+ state.disable_rendering
37
+ end
61
38
 
62
- else
63
- renderstate << node if self.rendering_enabled?
64
- end
39
+ # Set the tag state to track whether or not rendering has been enabled during the
40
+ # 'if' for an 'else' or 'elsif' tag.
41
+ state.with_tag_data( :rendering_was_enabled => state.rendering_enabled? ) do
42
+ super
65
43
  end
44
+
45
+ state.enable_rendering
46
+ return nil
66
47
  end
67
48
 
49
+
68
50
  end # class Inversion::Template::IfTag
69
51
 
@@ -34,7 +34,8 @@ class Inversion::Template::ImportTag < Inversion::Template::Tag
34
34
  ### Merge the inherited renderstate into the current template's +renderstate+.
35
35
  def render( renderstate )
36
36
  if (( cstate = renderstate.containerstate ))
37
- self.log.debug "Importing inherited attributes: %p from %p" % [ @attributes, cstate.attributes ]
37
+ self.log.debug "Importing inherited attributes: %p from %p" %
38
+ [ @attributes, cstate.attributes ]
38
39
 
39
40
  # Pick out the attributes that are being imported
40
41
  inherited_attrs = @attributes.inject( {} ) do |attrs, key|
@@ -43,6 +43,8 @@ class Inversion::Template::IncludeTag < Inversion::Template::Tag
43
43
  end
44
44
 
45
45
 
46
+ ### Parser callback -- append the nodes from the included template onto the
47
+ ### tree of the including template.
46
48
  def after_appending( parsestate )
47
49
  parsestate.append_tree( @included_template.node_tree )
48
50
  end
@@ -5,7 +5,7 @@ require 'inversion/mixins'
5
5
  require 'inversion/template' unless defined?( Inversion::Template )
6
6
 
7
7
  # Inversion template node base class. Template text is parsed by the
8
- # Inversion::Template::Parser into nodes, and appended to a tree
8
+ # Inversion::Parser into nodes, and appended to a tree
9
9
  # that is later walked when the template is rendered.
10
10
  #
11
11
  # This class is abstract; it just defines the API that other nodes
@@ -41,6 +41,7 @@ class Inversion::Template::Tag < Inversion::Template::Node
41
41
  def self::inherited( subclass )
42
42
  # Inversion.log.debug "%p inherited from %p" % [ subclass, self ]
43
43
  Inversion::Template::Tag.derivatives << subclass
44
+ Inversion.log.debug "Loaded tag type %p" % [ subclass ]
44
45
  super
45
46
  end
46
47
 
@@ -58,8 +59,8 @@ class Inversion::Template::Tag < Inversion::Template::Node
58
59
 
59
60
  Gem.find_files( TAG_PLUGIN_PATTERN ).each do |tagfile|
60
61
  tagname = tagfile[ %r{/(\w+)tag\.rb$}, 1 ].untaint
62
+ next unless tagname
61
63
 
62
- Inversion.log.debug "Loading tag type %p from %p" % [ tagname, tagfile ]
63
64
  self.load( tagfile )
64
65
 
65
66
  # Inversion.log.debug "Looking for class for %p tag" % [ tagname ]
@@ -93,7 +94,9 @@ class Inversion::Template::Tag < Inversion::Template::Node
93
94
 
94
95
  ### Safely load the specified +tagfile+.
95
96
  def self::load( tagfile )
96
- require( tagfile )
97
+ tagrequire = tagfile[ %r{inversion/template/\w+tag} ] or
98
+ raise "tag file %p doesn't look like a tag plugin" % [ tagfile ]
99
+ require( tagrequire )
97
100
  rescue => err
98
101
  Inversion.log.error "%s while loading tag plugin %p: %s" %
99
102
  [ err.class.name, tagfile, err.message ]
@@ -3,8 +3,7 @@
3
3
 
4
4
  require 'inversion/template/node'
5
5
 
6
- # Inversion text node class -- static content in templates between tags are contained
7
- # in a text node.
6
+ # Inversion text node class -- container for static content in templates between tags.
8
7
  class Inversion::Template::TextNode < Inversion::Template::Node
9
8
  include Inversion::Loggable
10
9
 
@@ -4,7 +4,6 @@
4
4
  require 'inversion/mixins'
5
5
  require 'inversion/template/attrtag'
6
6
  require 'inversion/template/containertag'
7
- require 'inversion/template/conditionaltag'
8
7
  require 'inversion/template/elsetag'
9
8
 
10
9
 
@@ -20,40 +19,31 @@ require 'inversion/template/elsetag'
20
19
  #
21
20
  class Inversion::Template::UnlessTag < Inversion::Template::AttrTag
22
21
  include Inversion::Loggable,
23
- Inversion::Template::ContainerTag,
24
- Inversion::Template::ConditionalTag
22
+ Inversion::Template::ContainerTag
25
23
 
26
24
  # Inherits AttrTag's tag patterns
27
25
 
28
26
  ### Render the tag's contents if the condition is true, or any else or elsif sections
29
27
  ### if the condition isn't true.
30
28
  def render( state )
31
- self.enable_rendering unless super
32
- self.render_subnodes( state )
33
29
 
34
- return state
35
- end
30
+ # Start out with rendering *disabled* if the tag body evaluates trueishly
31
+ if self.evaluate( state )
32
+ self.log.debug "Initial state was TRUE; disabling rendering"
33
+ state.disable_rendering
34
+ else
35
+ self.log.debug "Initial state was FALSE; enabling rendering"
36
+ state.enable_rendering
37
+ end
36
38
 
37
- ### Render the tag's subnodes according to the tag's logical state.
38
- def render_subnodes( renderstate )
39
- self.log.debug "Rendering subnodes. Rendering initially %s" %
40
- [ self.rendering_enabled? ? "enabled" : "disabled" ]
41
-
42
- # walk the subtree, modifying the logic flags for else and elsif tags,
43
- # and rendering nodes if rendering is enabled
44
- self.subnodes.each do |node|
45
- if node.is_a?( Inversion::Template::ElseTag )
46
- self.log.debug " logic switch: %p..." % [ node ]
47
- if !self.rendering_was_enabled?
48
- self.enable_rendering
49
- else
50
- self.disable_rendering
51
- end
52
-
53
- else
54
- renderstate << node if self.rendering_enabled?
55
- end
39
+ # Set the tag state to track whether or not rendering has been enabled during the
40
+ # 'unless' for an 'else' tag.
41
+ state.with_tag_data( :rendering_was_enabled => state.rendering_enabled? ) do
42
+ self.render_subnodes( state )
56
43
  end
44
+
45
+ state.enable_rendering
46
+ return nil
57
47
  end
58
48
 
59
49
  end # class Inversion::Template::UnlessTag
@@ -19,12 +19,6 @@ class Inversion::Template::YieldTag < Inversion::Template::Tag
19
19
  include Inversion::Loggable
20
20
 
21
21
 
22
- ### Set up a YieldTag's instance variables.
23
- def initialize( * )
24
- @block_value = nil
25
- end
26
-
27
-
28
22
  ######
29
23
  public
30
24
  ######
@@ -34,7 +28,7 @@ class Inversion::Template::YieldTag < Inversion::Template::Tag
34
28
  def before_rendering( renderstate )
35
29
  if renderstate.block
36
30
  self.log.debug "Yielding to %p before rendering." % [ renderstate.block ]
37
- @block_value = renderstate.block.call( renderstate )
31
+ renderstate.tag_data[ self ] = renderstate.block.call( renderstate )
38
32
  self.log.debug " render block returned: %p" % [ @block_value ]
39
33
  end
40
34
  end
@@ -44,8 +38,9 @@ class Inversion::Template::YieldTag < Inversion::Template::Tag
44
38
  ### #before_rendering (if there was a block).
45
39
  def render( renderstate )
46
40
  self.log.debug "Rendering as block return value: %p" % [ @block_value ]
47
- return @block_value
41
+ return renderstate.tag_data[ self ]
48
42
  end
49
43
 
44
+
50
45
  end # class Inversion::Template::YieldTag
51
46