inversion 0.1.1 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
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