arrow 1.0.7

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 (198) hide show
  1. data/ChangeLog +1590 -0
  2. data/LICENSE +28 -0
  3. data/README +75 -0
  4. data/Rakefile +366 -0
  5. data/Rakefile.local +63 -0
  6. data/data/arrow/applets/TEMPLATE.rb.tpl +53 -0
  7. data/data/arrow/applets/args.rb +50 -0
  8. data/data/arrow/applets/config.rb +55 -0
  9. data/data/arrow/applets/error.rb +63 -0
  10. data/data/arrow/applets/files.rb +46 -0
  11. data/data/arrow/applets/inspect.rb +46 -0
  12. data/data/arrow/applets/nosuchapplet.rb +31 -0
  13. data/data/arrow/applets/status.rb +92 -0
  14. data/data/arrow/applets/test.rb +133 -0
  15. data/data/arrow/applets/tutorial/counter.rb +96 -0
  16. data/data/arrow/applets/tutorial/dingus.rb +67 -0
  17. data/data/arrow/applets/tutorial/hello.rb +34 -0
  18. data/data/arrow/applets/tutorial/hello2.rb +73 -0
  19. data/data/arrow/applets/tutorial/imgtext.rb +90 -0
  20. data/data/arrow/applets/tutorial/imgtext2.rb +286 -0
  21. data/data/arrow/applets/tutorial/index.rb +36 -0
  22. data/data/arrow/applets/tutorial/logo.rb +98 -0
  23. data/data/arrow/applets/tutorial/memcache.rb +61 -0
  24. data/data/arrow/applets/tutorial/missing.rb +37 -0
  25. data/data/arrow/applets/tutorial/protected.rb +100 -0
  26. data/data/arrow/applets/tutorial/redirector.rb +52 -0
  27. data/data/arrow/applets/tutorial/rndimages.rb +159 -0
  28. data/data/arrow/applets/tutorial/sharenotes.rb +83 -0
  29. data/data/arrow/applets/tutorial/subclassed-hello.rb +32 -0
  30. data/data/arrow/applets/tutorial/superhello.rb +72 -0
  31. data/data/arrow/applets/tutorial/timeclock.rb +78 -0
  32. data/data/arrow/applets/view-applet.rb +123 -0
  33. data/data/arrow/applets/view-template.rb +85 -0
  34. data/data/arrow/applets/wiki.rb +274 -0
  35. data/data/arrow/templates/TEMPLATE.tmpl.tpl +36 -0
  36. data/data/arrow/templates/applet-status.tmpl +153 -0
  37. data/data/arrow/templates/args-display.tmpl +120 -0
  38. data/data/arrow/templates/config/display-table.tmpl +36 -0
  39. data/data/arrow/templates/config/display.tmpl +36 -0
  40. data/data/arrow/templates/counter-deleted.tmpl +33 -0
  41. data/data/arrow/templates/counter.tmpl +59 -0
  42. data/data/arrow/templates/dingus.tmpl +55 -0
  43. data/data/arrow/templates/enumtable.tmpl +8 -0
  44. data/data/arrow/templates/error-display.tmpl +92 -0
  45. data/data/arrow/templates/filemap.tmpl +89 -0
  46. data/data/arrow/templates/hello-world-src.tmpl +34 -0
  47. data/data/arrow/templates/hello-world.tmpl +60 -0
  48. data/data/arrow/templates/imgtext/fontlist.tmpl +46 -0
  49. data/data/arrow/templates/imgtext/form.tmpl +70 -0
  50. data/data/arrow/templates/imgtext/reload-error.tmpl +40 -0
  51. data/data/arrow/templates/imgtext/reload.tmpl +55 -0
  52. data/data/arrow/templates/inspect/display.tmpl +80 -0
  53. data/data/arrow/templates/loginform.tmpl +64 -0
  54. data/data/arrow/templates/logout.tmpl +32 -0
  55. data/data/arrow/templates/memcache/display.tmpl +41 -0
  56. data/data/arrow/templates/navbar.incl +27 -0
  57. data/data/arrow/templates/nosuchapplet.tmpl +32 -0
  58. data/data/arrow/templates/printsource.tmpl +35 -0
  59. data/data/arrow/templates/protected.tmpl +36 -0
  60. data/data/arrow/templates/rndimages.tmpl +38 -0
  61. data/data/arrow/templates/service-response.tmpl +13 -0
  62. data/data/arrow/templates/sharenotes/display.tmpl +38 -0
  63. data/data/arrow/templates/status.tmpl +120 -0
  64. data/data/arrow/templates/templateviewer.tmpl +43 -0
  65. data/data/arrow/templates/test/harness.tmpl +57 -0
  66. data/data/arrow/templates/test/list.tmpl +48 -0
  67. data/data/arrow/templates/test/problem.tmpl +42 -0
  68. data/data/arrow/templates/tutorial/index.tmpl +37 -0
  69. data/data/arrow/templates/tutorial/missingapplet.tmpl +29 -0
  70. data/data/arrow/templates/view-applet-nosuch.tmpl +32 -0
  71. data/data/arrow/templates/view-applet.tmpl +40 -0
  72. data/data/arrow/templates/view-template.tmpl +83 -0
  73. data/data/arrow/templates/wiki/formerror.tmpl +47 -0
  74. data/data/arrow/templates/wiki/markup_help.incl +6 -0
  75. data/data/arrow/templates/wiki/new.tmpl +56 -0
  76. data/data/arrow/templates/wiki/new_system.tmpl +122 -0
  77. data/data/arrow/templates/wiki/sectionlist.tmpl +43 -0
  78. data/data/arrow/templates/wiki/show.tmpl +34 -0
  79. data/docs/manual/layouts/default.page +43 -0
  80. data/docs/manual/lib/api-filter.rb +81 -0
  81. data/docs/manual/lib/editorial-filter.rb +64 -0
  82. data/docs/manual/lib/examples-filter.rb +244 -0
  83. data/docs/manual/lib/links-filter.rb +117 -0
  84. data/lib/apache/fakerequest.rb +448 -0
  85. data/lib/apache/logger.rb +33 -0
  86. data/lib/arrow.rb +51 -0
  87. data/lib/arrow/acceptparam.rb +207 -0
  88. data/lib/arrow/applet.rb +725 -0
  89. data/lib/arrow/appletmixins.rb +218 -0
  90. data/lib/arrow/appletregistry.rb +590 -0
  91. data/lib/arrow/applettestcase.rb +503 -0
  92. data/lib/arrow/broker.rb +255 -0
  93. data/lib/arrow/cache.rb +176 -0
  94. data/lib/arrow/config-loaders/yaml.rb +75 -0
  95. data/lib/arrow/config.rb +615 -0
  96. data/lib/arrow/constants.rb +24 -0
  97. data/lib/arrow/cookie.rb +359 -0
  98. data/lib/arrow/cookieset.rb +108 -0
  99. data/lib/arrow/dispatcher.rb +368 -0
  100. data/lib/arrow/dispatcherloader.rb +50 -0
  101. data/lib/arrow/exceptions.rb +61 -0
  102. data/lib/arrow/fallbackhandler.rb +48 -0
  103. data/lib/arrow/formvalidator.rb +631 -0
  104. data/lib/arrow/htmltokenizer.rb +343 -0
  105. data/lib/arrow/logger.rb +488 -0
  106. data/lib/arrow/logger/apacheoutputter.rb +69 -0
  107. data/lib/arrow/logger/arrayoutputter.rb +63 -0
  108. data/lib/arrow/logger/coloroutputter.rb +111 -0
  109. data/lib/arrow/logger/fileoutputter.rb +96 -0
  110. data/lib/arrow/logger/htmloutputter.rb +54 -0
  111. data/lib/arrow/logger/outputter.rb +123 -0
  112. data/lib/arrow/mixins.rb +425 -0
  113. data/lib/arrow/monkeypatches.rb +94 -0
  114. data/lib/arrow/object.rb +117 -0
  115. data/lib/arrow/path.rb +196 -0
  116. data/lib/arrow/service.rb +447 -0
  117. data/lib/arrow/session.rb +289 -0
  118. data/lib/arrow/session/dbstore.rb +100 -0
  119. data/lib/arrow/session/filelock.rb +160 -0
  120. data/lib/arrow/session/filestore.rb +132 -0
  121. data/lib/arrow/session/id.rb +98 -0
  122. data/lib/arrow/session/lock.rb +253 -0
  123. data/lib/arrow/session/md5id.rb +42 -0
  124. data/lib/arrow/session/nulllock.rb +42 -0
  125. data/lib/arrow/session/posixlock.rb +166 -0
  126. data/lib/arrow/session/sha1id.rb +54 -0
  127. data/lib/arrow/session/store.rb +366 -0
  128. data/lib/arrow/session/usertrackid.rb +52 -0
  129. data/lib/arrow/spechelpers.rb +73 -0
  130. data/lib/arrow/template.rb +713 -0
  131. data/lib/arrow/template/attr.rb +31 -0
  132. data/lib/arrow/template/call.rb +31 -0
  133. data/lib/arrow/template/comment.rb +33 -0
  134. data/lib/arrow/template/container.rb +118 -0
  135. data/lib/arrow/template/else.rb +41 -0
  136. data/lib/arrow/template/elsif.rb +44 -0
  137. data/lib/arrow/template/escape.rb +53 -0
  138. data/lib/arrow/template/export.rb +87 -0
  139. data/lib/arrow/template/for.rb +145 -0
  140. data/lib/arrow/template/if.rb +78 -0
  141. data/lib/arrow/template/import.rb +119 -0
  142. data/lib/arrow/template/include.rb +206 -0
  143. data/lib/arrow/template/iterator.rb +208 -0
  144. data/lib/arrow/template/nodes.rb +734 -0
  145. data/lib/arrow/template/parser.rb +571 -0
  146. data/lib/arrow/template/prettyprint.rb +53 -0
  147. data/lib/arrow/template/render.rb +191 -0
  148. data/lib/arrow/template/selectlist.rb +94 -0
  149. data/lib/arrow/template/set.rb +87 -0
  150. data/lib/arrow/template/timedelta.rb +81 -0
  151. data/lib/arrow/template/unless.rb +78 -0
  152. data/lib/arrow/template/urlencode.rb +51 -0
  153. data/lib/arrow/template/yield.rb +139 -0
  154. data/lib/arrow/templatefactory.rb +125 -0
  155. data/lib/arrow/testcase.rb +567 -0
  156. data/lib/arrow/transaction.rb +608 -0
  157. data/rake/191_compat.rb +26 -0
  158. data/rake/dependencies.rb +76 -0
  159. data/rake/documentation.rb +114 -0
  160. data/rake/helpers.rb +502 -0
  161. data/rake/hg.rb +282 -0
  162. data/rake/manual.rb +787 -0
  163. data/rake/packaging.rb +129 -0
  164. data/rake/publishing.rb +278 -0
  165. data/rake/style.rb +62 -0
  166. data/rake/svn.rb +668 -0
  167. data/rake/testing.rb +187 -0
  168. data/rake/verifytask.rb +64 -0
  169. data/spec/arrow/acceptparam_spec.rb +157 -0
  170. data/spec/arrow/applet_spec.rb +575 -0
  171. data/spec/arrow/appletmixins_spec.rb +409 -0
  172. data/spec/arrow/appletregistry_spec.rb +294 -0
  173. data/spec/arrow/broker_spec.rb +153 -0
  174. data/spec/arrow/config_spec.rb +224 -0
  175. data/spec/arrow/cookieset_spec.rb +164 -0
  176. data/spec/arrow/dispatcher_spec.rb +137 -0
  177. data/spec/arrow/dispatcherloader_spec.rb +65 -0
  178. data/spec/arrow/formvalidator_spec.rb +781 -0
  179. data/spec/arrow/logger_spec.rb +346 -0
  180. data/spec/arrow/mixins_spec.rb +120 -0
  181. data/spec/arrow/service_spec.rb +645 -0
  182. data/spec/arrow/session_spec.rb +121 -0
  183. data/spec/arrow/template/iterator_spec.rb +222 -0
  184. data/spec/arrow/templatefactory_spec.rb +185 -0
  185. data/spec/arrow/transaction_spec.rb +319 -0
  186. data/spec/arrow_spec.rb +37 -0
  187. data/spec/lib/appletmatchers.rb +281 -0
  188. data/spec/lib/constants.rb +77 -0
  189. data/spec/lib/helpers.rb +41 -0
  190. data/spec/lib/matchers.rb +44 -0
  191. data/tests/cookie.tests.rb +310 -0
  192. data/tests/path.tests.rb +157 -0
  193. data/tests/session.tests.rb +111 -0
  194. data/tests/session_id.tests.rb +82 -0
  195. data/tests/session_lock.tests.rb +191 -0
  196. data/tests/session_store.tests.rb +53 -0
  197. data/tests/template.tests.rb +1360 -0
  198. metadata +339 -0
@@ -0,0 +1,145 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'arrow/exceptions'
4
+ require 'arrow/path'
5
+ require 'arrow/template'
6
+ require 'arrow/template/nodes'
7
+ require 'arrow/template/iterator'
8
+
9
+ # The Arrow::Template::ForDirective class, a derivative of
10
+ # Arrow::Template::BracketingDirective. This is the class which defines the
11
+ # behaviour of the 'for' template directive.
12
+ #
13
+ # == Syntax
14
+ #
15
+ # <?for <arglist> in <obj>?>...<?end for?>
16
+ #
17
+ # This directive iterates over all the items in an Enumerable object (via the
18
+ # #entities method), rendering the contents once for each object. The specified
19
+ # #<em>arglist</em> is similar to Ruby's argument lists: it supports defaults,
20
+ # as well as array (e.g., <tt>*rest</tt>) and hash arguments.
21
+ #
22
+ # While the contents are rendering, a special attribute named <em>iterator</em>
23
+ # is set to an Arrow::Template::Iterator object, which can be used to get
24
+ # information about the iteration itself. This directive doesn't add anything to
25
+ # the output directly, but relies on its subnodes for content.
26
+ #
27
+ # This directive only works with Enumerable objects; for other objects with
28
+ # iterators or blocks, use the <?yield?> directive.
29
+ #
30
+ # === Examples
31
+ #
32
+ # <!-- Iterate over the headers in a request -->
33
+ # <?for name, value in request.headers_in ?>
34
+ # <strong><?attr name?>:</strong> <?attr value?><br/>
35
+ # <?end for?>
36
+ #
37
+ # <!-- Same thing, but this time in a table with alternating styles for each
38
+ # row. -->
39
+ # <table>
40
+ # <?for name, value in request.headers_in ?>
41
+ # <?if iterator.even? ?>
42
+ # <tr class="even-row">
43
+ # <?else?>
44
+ # <tr class="odd-row">
45
+ # <?end if?>
46
+ # <td><?attr name?></td> <td><?attr value?></td>
47
+ # </tr>
48
+ # <?end for?>
49
+ # </table>
50
+ #
51
+ # <!-- Pair up words with their lengths and sort them shortest first, then
52
+ # print them out with their lengths -->
53
+ # <?for word, length in tests.
54
+ # collect {|item| [item, item.length]}.
55
+ # sort_by {|item| item[1]} ?>
56
+ # <?attr word?>: <?attr length?>
57
+ # <?end for?>
58
+ #
59
+ # == Authors
60
+ #
61
+ # * Michael Granger <ged@FaerieMUD.org>
62
+ #
63
+ # Please see the file LICENSE in the top-level directory for licensing details.
64
+ #
65
+ class Arrow::Template::ForDirective < Arrow::Template::BracketingDirective # :nodoc:
66
+ include Arrow::Template::Parser::Patterns
67
+
68
+ # The regexp for matching the 'in' part of the directive
69
+ IN = WHITESPACE + /in/i + WHITESPACE
70
+
71
+
72
+ #############################################################
73
+ ### I N S T A N C E M E T H O D S
74
+ #############################################################
75
+
76
+ ### Create a new Arrow::Template::ForDirective object.
77
+ def initialize( body, parser, state )
78
+ @args = []
79
+ @pureargs = []
80
+ super
81
+ end
82
+
83
+
84
+ ######
85
+ public
86
+ ######
87
+
88
+ # The argument list for the iterator, with sigils and defaults, if any.
89
+ attr_reader :args
90
+
91
+ # The argument list for the iterator, with any sigils and defaults
92
+ # stripped away.
93
+ attr_reader :pureargs
94
+
95
+
96
+ #########
97
+ protected
98
+ #########
99
+
100
+ ### Parse the contents of the directive.
101
+ def parse_directive_contents( parser, state )
102
+ @args, @pureargs = parser.scan_for_arglist( state )
103
+ return nil unless @args
104
+
105
+ state.scanner.skip( IN ) or
106
+ raise Arrow::ParseError, "no 'in' for 'for'"
107
+
108
+ super
109
+ end
110
+
111
+
112
+ ### Render the directive's bracketed nodes once for each item in the
113
+ ### iterated content.
114
+ def render_subnodes( attribute, template, scope )
115
+ res = []
116
+
117
+ iterator = Arrow::Template::Iterator.new( attribute )
118
+ iterator.each {|iter,*blockArgs|
119
+ #self.log.debug "[FOR] Block args are: %p" % [ blockArgs ]
120
+
121
+ # Make an attributes hash from the pure args of left side of the
122
+ # 'for'.
123
+ attributes = {}
124
+ blockArgs.zip( self.pureargs ) {|pair|
125
+ attributes[ pair[1] ] = pair[0]
126
+ }
127
+ attributes['iterator'] = iter
128
+
129
+ # Process the nodes inside the 'for' block with the args being
130
+ # overridden.
131
+ #self.log.debug " [FOR] calling into new scope with overridden " +
132
+ # "attributes: %p" % [ attributes ]
133
+ template.with_overridden_attributes( scope, attributes ) {|template|
134
+ res << template.render( @subnodes, scope )
135
+ }
136
+ }
137
+
138
+ return *res
139
+ end
140
+
141
+
142
+
143
+ end # class Arrow::Template::ForDirective
144
+
145
+
@@ -0,0 +1,78 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'arrow/template'
4
+ require 'arrow/template/nodes'
5
+
6
+ # The Arrow::Template::IfDirective class, a derivative of
7
+ # Arrow::Template::BracketingDirective. Instances of this class represent a
8
+ # section of a template that is rendered conditionally.
9
+ #
10
+ # The formats the directive supports are:
11
+ #
12
+ # <?if <name>?>...<?end if?>
13
+ # <?if <name>.<methodchain>?>...<?end if?>
14
+ # <?if <name> (matches|=~) <regex>?>...<?end if?>
15
+ # <?if <name>.<methodchain> (matches|=~) <regex>?>...<?end if?>
16
+ #
17
+ # Note that this directive does not support all possible Ruby expressions in the
18
+ # conditional, and must have a valid associated identifier (the <em>name</em>
19
+ # bit).
20
+ #
21
+ # == Authors
22
+ #
23
+ # * Michael Granger <ged@FaerieMUD.org>
24
+ #
25
+ # Please see the file LICENSE in the top-level directory for licensing details.
26
+ #
27
+ class Arrow::Template::IfDirective < Arrow::Template::BracketingDirective # :nodoc:
28
+ include Arrow::Template::ConditionalDirective
29
+
30
+ require 'arrow/template/else'
31
+ require 'arrow/template/elsif'
32
+
33
+
34
+ #############################################################
35
+ ### I N S T A N C E M E T H O D S
36
+ #############################################################
37
+
38
+ #########
39
+ protected
40
+ #########
41
+
42
+ ### Render the contents of the conditional if it evaluates to +true+, or
43
+ ### the nodes after 'elsif' or 'else' subnodes if their conditions are
44
+ ### met.
45
+ def render_contents( template, scope )
46
+ cond = hasBeenTrue = self.evaluate( template, scope )
47
+
48
+ nodes = []
49
+
50
+ # Now splice out the chunk of nodes that should be rendered based on
51
+ # the conditional.
52
+ @subnodes.each do |node|
53
+ case node
54
+ when Arrow::Template::ElsifDirective
55
+ if !hasBeenTrue
56
+ cond = hasBeenTrue = node.evaluate( template, scope )
57
+ else
58
+ cond = false
59
+ end
60
+
61
+ when Arrow::Template::ElseDirective
62
+ if !hasBeenTrue
63
+ cond = hasBeenTrue = true
64
+ else
65
+ cond = false
66
+ end
67
+
68
+ else
69
+ nodes.push( node ) if cond
70
+ end
71
+ end
72
+
73
+ return template.render( nodes, scope )
74
+ end
75
+
76
+
77
+
78
+ end # class Arrow::Template::IfDirective
@@ -0,0 +1,119 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'arrow/template/nodes'
4
+ require 'arrow/template/parser'
5
+
6
+ # The Arrow::Template::ImportDirective class, a derivative of
7
+ # Arrow::Template::Directive. This is the class which defines the behaviour of
8
+ # the 'import' template directive.
9
+ #
10
+ # === Syntax
11
+ #
12
+ # <?import foo?>
13
+ # <?import foo as superfoo?>
14
+ # <?import foo, bar?>
15
+ # <?import foo as superfoo, bar, baz as bazish?>
16
+ #
17
+ # == Authors
18
+ #
19
+ # * Michael Granger <ged@FaerieMUD.org>
20
+ #
21
+ # Please see the file LICENSE in the top-level directory for licensing details.
22
+ #
23
+ class Arrow::Template::ImportDirective < Arrow::Template::Directive # :nodoc:
24
+ include Arrow::Template::Parser::Patterns
25
+
26
+ # SVN Revision
27
+ SVNRev = %q$Rev$
28
+
29
+ # SVN Id
30
+ SVNId = %q$Id$
31
+
32
+ # Various patterns
33
+ SIMPLEIMPORT = CAPTURE[ IDENTIFIER ]
34
+ ALIASIMPORT = CAPTURE[ IDENTIFIER ] + /\s+as\s+/i + CAPTURE[ IDENTIFIER ]
35
+
36
+
37
+ #############################################################
38
+ ### C L A S S M E T H O D S
39
+ #############################################################
40
+
41
+ ### Disallow formats
42
+ def self::allows_format?; false; end
43
+
44
+
45
+ #############################################################
46
+ ### I N S T A N C E M E T H O D S
47
+ #############################################################
48
+
49
+ ### Create a new ImportDirective object.
50
+ def initialize( type, parser, state )
51
+ @imports = {}
52
+ super
53
+ end
54
+
55
+
56
+ ######
57
+ public
58
+ ######
59
+
60
+ # An Array of Regexp objects which match the names of attributes to be
61
+ # imported.
62
+ attr_reader :patterns
63
+
64
+
65
+ ### Add the imported attributes when this node is rendered.
66
+ def render( template, scope )
67
+ imports = []
68
+
69
+ if (( st = template._enclosing_template ))
70
+ @imports.each do |source,dest|
71
+ imports << "%s as %s (%p)" %
72
+ [ source, dest, st._attributes[source] ]
73
+ template._attributes[dest] = st._attributes[source]
74
+ end
75
+ end
76
+
77
+ if template._config[:debuggingComments]
78
+ return template.render_comment( "Importing: " + imports.join(", ") )
79
+ else
80
+ return ''
81
+ end
82
+ end
83
+
84
+
85
+ #########
86
+ protected
87
+ #########
88
+
89
+ ### Parse the contents of the directive.
90
+ def parse_directive_contents( parser, state )
91
+ super
92
+
93
+ state.scanner.skip( WHITESPACE )
94
+ #self.log.debug "Scanning for tag middle at: '%20s'" % state.scanner.rest
95
+
96
+ body = state.scanner.scan( state.tag_middle ) or return nil
97
+ #self.log.debug "Found body = %p" % body
98
+
99
+ body.strip.split( /\s*,\s*/ ).each do |import|
100
+ #self.log.debug "Parsing import: %p" % import
101
+ case import
102
+ when ALIASIMPORT
103
+ @imports[ $1 ] = $2
104
+ #self.log.debug "Alias import: %s => %s" %
105
+ # [ $1, $2 ]
106
+
107
+ when SIMPLEIMPORT
108
+ @imports[ $1 ] = $1
109
+ #self.log.debug "Simple import: %s" % $1
110
+
111
+ else
112
+ raise Arrow::ParseError, "Failed to parse body: %p" % body
113
+ end
114
+ end
115
+
116
+ return true
117
+ end
118
+
119
+ end # class Arrow::Template::ImportDirective
@@ -0,0 +1,206 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'arrow/exceptions'
4
+ require 'arrow/path'
5
+ require 'arrow/template/nodes'
6
+
7
+ # The Arrow::Template::IncludeDirective class, a derivative of
8
+ # Arrow::Template::Directive. This is the class which defines the
9
+ # behaviour of the 'include' template directive.
10
+ #
11
+ # == Syntax
12
+ #
13
+ # <!-- Include a subtemplate directly -->
14
+ # <?include subtemplate.tmpl ?>
15
+ #
16
+ # <!-- Include a subtemplate as a callable sub-entity -->
17
+ # <?include subtemplate.tmpl as sub ?>
18
+ #
19
+ # == Example
20
+ # If 'subtemplate.tmpl' contains:
21
+ # <?attr foo?>
22
+ # and the main template contains:
23
+ # <?include subtemplate.tmpl?>
24
+ # <?include subtemplate.tmpl as sub?>
25
+ # and the code (+template+ is the Template object) looks like:
26
+ # template.foo = "argle"
27
+ # template.sub.foo = "bargle"
28
+ # the template will render as:
29
+ # argle
30
+ # bargle
31
+ #
32
+ # == Authors
33
+ #
34
+ # * Michael Granger <ged@FaerieMUD.org>
35
+ #
36
+ # Please see the file LICENSE in the top-level directory for licensing details.
37
+ #
38
+ class Arrow::Template::IncludeDirective < Arrow::Template::Directive # :nodoc:
39
+ include Arrow::Template::Parser::Patterns
40
+
41
+ # SVN Revision
42
+ SVNRev = %q$Rev$
43
+
44
+ # SVN Id
45
+ SVNId = %q$Id$
46
+
47
+
48
+
49
+ #############################################################
50
+ ### I N S T A N C E M E T H O D S
51
+ #############################################################
52
+
53
+ ### Initialize a new IncludeDirective object.
54
+ def initialize( type, parser, state ) # :notnew:
55
+ @nodes = nil
56
+ @identifier = nil
57
+ @subtemplate = nil
58
+
59
+ state[:includeStack] ||= []
60
+ super
61
+ end
62
+
63
+
64
+ ######
65
+ public
66
+ ######
67
+
68
+ # The identifier associated with an include that has an 'as <name>'
69
+ # part.
70
+ attr_accessor :identifier
71
+ alias_method :name, :identifier
72
+ alias_method :name=, :identifier=
73
+
74
+ # The template object associated with an include that has an 'as <name>'
75
+ # part.
76
+ attr_accessor :subtemplate
77
+
78
+
79
+ ### Add the nodes that were included to the given +template+ object.
80
+ def add_to_template( template )
81
+ #self.log.debug "Installing an include's subnodes"
82
+
83
+ if @identifier
84
+ template.install_node( self )
85
+ template.send( "#{@identifier}=", @subtemplate )
86
+ targetTemplate = @subtemplate
87
+ else
88
+ targetTemplate = template
89
+ end
90
+
91
+ @nodes.each do |node|
92
+ targetTemplate.install_node( node )
93
+ end
94
+ end
95
+
96
+
97
+ ### Render the include.
98
+ def render( template, scope )
99
+ rary = super
100
+
101
+ # Render the included nodes
102
+ if @subtemplate
103
+ #self.log.debug "Rendering an include's subtemplate"
104
+ rary.push( *(@subtemplate.render) )
105
+ else
106
+ #self.log.debug "Rendering an include's subnodes"
107
+ rary.push( *(template.render( @nodes, scope )) )
108
+ end
109
+
110
+ return rary
111
+ end
112
+
113
+
114
+ ### Return an HTML fragment that can be used to represent the node
115
+ ### symbolically in a web-based introspection interface.
116
+ def to_html
117
+ nodeclass = self.css_class
118
+
119
+ if @subtemplate
120
+ subtree = @subtemplate._syntax_tree
121
+ html = ''
122
+ html << %q{<strong>#%s</strong> } % @identifier
123
+ html <<
124
+ %q{<div class="node-subtemplate %s-node-subtemplate">
125
+ <div class="node-subtemplate-head %s-node-subtemplate-head"
126
+ >Subtemplate</div>%s</div>} % [
127
+ nodeclass, nodeclass,
128
+ subtree.collect {|node| node.to_html}.join(''),
129
+ ]
130
+
131
+ super { html }
132
+ else
133
+ super {
134
+ %q{<div class="node-subtree %s-node-subtree">
135
+ <div class="node-subtree-head %s-node-subtree-head"
136
+ >Subnodes</div>%s</div>} % [
137
+ nodeclass, nodeclass,
138
+ @nodes.collect {|node| node.to_html}.join
139
+ ]
140
+ }
141
+ end
142
+ end
143
+
144
+
145
+ #########
146
+ protected
147
+ #########
148
+
149
+ ### Parse the contents of the directive, loading the specified file into
150
+ ### the scanner, if possible.
151
+ def parse_directive_contents( parser, state )
152
+ filename = parser.scan_for_pathname( state ) or
153
+ raise Arrow::ParseError, "No filename found for 'include'"
154
+ filename.untaint
155
+
156
+ state.scanner.skip( WHITESPACE )
157
+ if state.scanner.scan( /\bas\b/i )
158
+ @identifier = parser.scan_for_identifier( state )
159
+ end
160
+
161
+ # Try to do the include. Handle errors ourselves since this happens
162
+ # during parse time.
163
+ begin
164
+ #self.log.debug "Include stack is: ", state[:includeStack]
165
+
166
+ # Catch circular includes
167
+ if state[:includeStack].include?( filename )
168
+ raise Arrow::TemplateError, "Circular include: %s -> %s" %
169
+ [ state[:includeStack].join(" -> "), filename ]
170
+
171
+ # Parse the included file into nodes, passing the state from
172
+ # the current parse into the subparse.
173
+ else
174
+ initialData = state.data.dup
175
+ initialData[:includeStack].push filename
176
+
177
+ load_path = state.template._load_path
178
+ #self.log.debug "Load path from including template is: %p" %
179
+ # load_path
180
+ path = Arrow::Template.find_file( filename, load_path )
181
+ content = File.read( path )
182
+ content.untaint
183
+
184
+ #self.log.debug "initialData is: %p" % initialData
185
+ @nodes = parser.parse( content, state.template, initialData )
186
+ initialData[:includeStack].pop
187
+ end
188
+
189
+ # Some errors just turn into comment nodes
190
+ # :TODO: Make this configurable somehow?
191
+ rescue Arrow::TemplateError, IOError => err
192
+ msg = "#{err.class.name}: Include #{filename}: #{err.message}"
193
+ @nodes = [ Arrow::Template::CommentNode.new(msg) ]
194
+ end
195
+
196
+ # If the directive has an "as <id>" part, create the subtemplate
197
+ # that will be associated with that identifier.
198
+ if @identifier
199
+ @subtemplate = Arrow::Template.new( @nodes, state.template._config )
200
+ end
201
+
202
+ return true
203
+ end
204
+
205
+
206
+ end # class Arrow::Template::IncludeDirective