bijou 0.1.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 (53) hide show
  1. data/ChangeLog.txt +4 -0
  2. data/LICENSE.txt +58 -0
  3. data/README.txt +48 -0
  4. data/Rakefile +105 -0
  5. data/doc/INSTALL.rdoc +260 -0
  6. data/doc/README.rdoc +314 -0
  7. data/doc/releases/bijou-0.1.0.rdoc +60 -0
  8. data/examples/birthday/birthday.rb +34 -0
  9. data/examples/holiday/holiday.rb +61 -0
  10. data/examples/holiday/letterhead.txt +4 -0
  11. data/examples/holiday/signature.txt +9 -0
  12. data/examples/phishing/letter.txt +29 -0
  13. data/examples/phishing/letterhead.txt +4 -0
  14. data/examples/phishing/phishing.rb +21 -0
  15. data/examples/phishing/signature.txt +9 -0
  16. data/examples/profile/profile.rb +46 -0
  17. data/lib/bijou.rb +15 -0
  18. data/lib/bijou/backend.rb +542 -0
  19. data/lib/bijou/cgi/adapter.rb +201 -0
  20. data/lib/bijou/cgi/handler.rb +5 -0
  21. data/lib/bijou/cgi/request.rb +37 -0
  22. data/lib/bijou/common.rb +12 -0
  23. data/lib/bijou/component.rb +108 -0
  24. data/lib/bijou/config.rb +60 -0
  25. data/lib/bijou/console/adapter.rb +167 -0
  26. data/lib/bijou/console/handler.rb +4 -0
  27. data/lib/bijou/console/request.rb +26 -0
  28. data/lib/bijou/context.rb +431 -0
  29. data/lib/bijou/diagnostics.rb +87 -0
  30. data/lib/bijou/errorformatter.rb +322 -0
  31. data/lib/bijou/exception.rb +39 -0
  32. data/lib/bijou/filters.rb +107 -0
  33. data/lib/bijou/httprequest.rb +108 -0
  34. data/lib/bijou/httpresponse.rb +268 -0
  35. data/lib/bijou/lexer.rb +513 -0
  36. data/lib/bijou/minicgi.rb +159 -0
  37. data/lib/bijou/parser.rb +1026 -0
  38. data/lib/bijou/processor.rb +404 -0
  39. data/lib/bijou/prstringio.rb +400 -0
  40. data/lib/bijou/webrick/adapter.rb +174 -0
  41. data/lib/bijou/webrick/handler.rb +32 -0
  42. data/lib/bijou/webrick/request.rb +45 -0
  43. data/script/cgi.rb +25 -0
  44. data/script/console.rb +7 -0
  45. data/script/server.rb +7 -0
  46. data/test/t1.cfg +5 -0
  47. data/test/tc_config.rb +26 -0
  48. data/test/tc_filter.rb +25 -0
  49. data/test/tc_lexer.rb +120 -0
  50. data/test/tc_response.rb +103 -0
  51. data/test/tc_ruby.rb +62 -0
  52. data/test/tc_stack.rb +50 -0
  53. metadata +121 -0
data/doc/README.rdoc ADDED
@@ -0,0 +1,314 @@
1
+ = Bijou - A web page templating framework for Ruby
2
+
3
+ == Introduction
4
+
5
+ Bijou is a templating system for Ruby. It was inspired by Perl's HTML::Mason.
6
+ Bijou files are text or HTML files that support in-line Ruby. Bijou also
7
+ supports the inclusion of text and code from other sources, called methods
8
+ and components. Components may be shared between files. They may also be used
9
+ as containers (sometimes called templates or layouts in other environments).
10
+ By chaining together components and containers, an arbitrarily sophisticated
11
+ system may be developed.
12
+
13
+ === Example
14
+
15
+ This example illustrates some of the similarities and differences between
16
+ Bijou and Mason. We'll use the canonical example here.
17
+
18
+ <% planet = 'World' %>
19
+ Hello, <%= planet %>!
20
+
21
+ This, of course, results in the following ouput:
22
+
23
+ Hello, world!
24
+
25
+ The syntax of Bijou was kept very close to that of Mason. However, some
26
+ differences do exist.
27
+
28
+ === Overview
29
+
30
+ The most basic Bijou file is a text or HTML file. No special markup is
31
+ required. When the file is first loaded, it will be compiled into a Ruby class
32
+ that renders its output to an object compatible with the target web server.
33
+
34
+ To include Ruby code, two special tag formats may be used: inline code
35
+ segments and output tags.
36
+
37
+ <% total = subtotal * tax_rate
38
+ print format_currency(total)
39
+ %>
40
+
41
+ <%= format_currency(total) %>
42
+
43
+ Code segments, which begin with <tt><%</tt>, may contain any Ruby code on
44
+ one line or across several. To render output to the target HTML stream,
45
+ either <tt>puts</tt>, <tt>print</tt>, or <tt>printf</tt> may be used.
46
+
47
+ Output tags begin with <tt><%=</tt> and the result of their evaluation
48
+ is rendered to the HTML stream automatically.
49
+
50
+ == Structure
51
+
52
+ There are basic three types of Bijou file, all derived from Bijou::Component.
53
+ The following terms are used to clarify meaning in the documentation. There
54
+ is very little difference between them in terms of syntax or operation.
55
+
56
+ - Pages
57
+ - Containers
58
+ - Components
59
+
60
+ A page is a stand-alone component, typically called directly by the web server.
61
+ A container is used by a page to provide a common layout. And a component is
62
+ a fragment that is used by other pages, containers, or components.
63
+
64
+ Although all three types are based on the class Bijou::Component, the term
65
+ component is usually used to refer to the specialized variety.
66
+
67
+ === Pages
68
+
69
+ Each Bijou file may contain a mixture of HTML markup and Ruby code. When a
70
+ document is requested by the web server, the server adapter invokes the
71
+ Bijou processor and attempts to locate a corresponding Bijou file. The
72
+ processor then interprets the file, execuing any Ruby code encountered
73
+ along the way.
74
+
75
+ <html>
76
+ <head>
77
+ <title>Example</title>
78
+ </head>
79
+ <body>
80
+ <%= "Welcome to Bijou" %>
81
+ </body>
82
+ </html>
83
+
84
+ This example is a stand-alone page that doesn't require any HTTP arguments.
85
+
86
+ === Arguments
87
+
88
+ When a file is called by the web server, the get and post parameters are
89
+ available via intrinsic objects on the component. Their union is available
90
+ via the implicit <tt>args</tt> parameter, which is a hash. In addition, a
91
+ top-level <tt><%args></tt> block may be defined to automatically marshal
92
+ the parameters so they are available as local variables, with or without
93
+ default values. For example:
94
+
95
+ <%args>
96
+ argument1 # This parameter is required, as there is no specified default.
97
+ argument2 => '' # If a value is not sent, this default will be used.
98
+ ...
99
+ </%args>
100
+
101
+ Here, the <tt>argument1</tt> value may be accessed using:
102
+
103
+ - <tt>argument1</tt> - The local variable declared using the <tt><%args></tt> block
104
+ - <tt>args[:argument1]</tt> - The implicit args hash parameter
105
+ - <tt>request.params[:argument1]</tt> - The intrinsic request object
106
+
107
+ A file may be a stand-alone module, which is invoked by the web server.
108
+ It may also be a component or a container. Components and containers have
109
+ the same syntax as normal modules, but they serve different purposes.
110
+
111
+ === Components
112
+
113
+ A component is a specialized Bijou file that is intended to be called by pages,
114
+ containers, and other components. It has the same markup and code syntax as a
115
+ stand-alone file. The primary difference is that the top-level <tt><%args></tt>
116
+ block does not specify HTTP parameters. Instead, it defines arguments that are
117
+ passed by the caller to the component via the component call, which uses the
118
+ the syntax
119
+ <tt><& <em>component</em> [<em>, argument1 => value1, argument2 => value2, ...</em>] &></tt>.
120
+
121
+ === Containers
122
+
123
+ Containers allow users to build re-usable templates, sometimes called layouts.
124
+ The container represents the 'outer' text and the 'inner' text is generated
125
+ by the associated page or content component.
126
+
127
+ Containers are like normal components. The only difference is that they
128
+ must contain a special call tag, <tt><& content &></tt>, which is where
129
+ the caller's output is placed during the rendering process. A component
130
+ references a container using the <tt>container</tt> directive.
131
+
132
+ For example, a page might start with the following directive. (Directives
133
+ are usually placed at the top.)
134
+
135
+ <%! container="../layouts/frontpage.rbb" %>
136
+ <h1>Introduction</h1>
137
+ ...
138
+
139
+ This directive would instruct the Bijou processor to load the front page
140
+ container as the 'outer' markup, substituting this page's content
141
+ (starting with <tt><h1>...</tt>) at the location of the container's
142
+ <tt><& content &></tt> tag. A simplified container might look like this
143
+
144
+ <html>
145
+ <head>
146
+ <title>Welcome</title>
147
+ </head>
148
+ <body>
149
+ <& content &>
150
+ </body>
151
+ </html>
152
+
153
+ Containers may contain methods and code just like normal components.
154
+ In addition to pages, containers and components may also specify
155
+ associated containers. In this way, containers may be chained together,
156
+ allowing for an arbitrary level of complexity.
157
+
158
+ == Syntax
159
+
160
+ A Bijou file contains normal text or HTML mixed with special markup. This
161
+ markup has a syntax similar to HTML, but it is designed to integrate Ruby
162
+ code in a way that supports the generation of dynamic content.
163
+
164
+ === Inline code
165
+ *Syntax*: <% <b>...</b> %>
166
+
167
+ Executes any Ruby code that is placed between the delimiters.
168
+
169
+ === Inline output
170
+ *Syntax*: <%= <em>expression</em> %>
171
+
172
+ Evalues the expression and prints the result.
173
+
174
+ === Method or Component Call
175
+ *Syntax*: <& <em>name</em> [<em>, argument1 => value1, argument2 => value2, ...</em>] &>
176
+
177
+ Calls the named method or component and displays the output.
178
+
179
+ Example:
180
+
181
+ <& copyright, name => 'Transgalactic Enterprises, Inc.', year => 2187 &>
182
+
183
+ This would call the method <tt><%method copyright></tt> or a component having
184
+ that filename, passing the specified arguments. The output of the method or
185
+ component call would be rendered in place of the call tag.
186
+
187
+ === Indirect Method or Component Call
188
+ *Syntax*: <&= <em>method</em> [<em>, argument1 => value1, argument2 => value2, ...</em>] &>
189
+
190
+ This syntax can be used to dynamically select which component or method to
191
+ call. The named method or component is first invoked without rendering the
192
+ result. Instead, the return value (assumed to be a string), is used to locate a
193
+ component or method, which is then invoked normally.
194
+
195
+ === Directive
196
+ *Syntax*: <%! [<em>name1 => value1, name2 => value2, ...</em>] %>
197
+
198
+ Directives are used to control various aspects of page generation and
199
+ evaluation. Examples include, <tt>container</tt>, <tt>base</tt>, and
200
+ <tt>include</tt>.
201
+
202
+ === Method
203
+ *Syntax*: <%method <em>name</em>> <b>...</b> </%method>
204
+
205
+ Methods may contain arbitrary markup, like the main section of a Bijou file.
206
+ Once a method has been defined, it may then be invoked by name, with or
207
+ without arguments, from the main section or from within other methods.
208
+
209
+ In addition, methods defined in a container may be overridden in a content
210
+ component. For example, a container could define a method called <tt>title</tt>
211
+ and call it like this.
212
+
213
+ <html>
214
+ <head>
215
+ <title><& title &></title>
216
+ ...
217
+ <& content &>
218
+ ...
219
+
220
+ <%method title>
221
+ Welcome to Transgalactic Enterprises
222
+ </%method>
223
+
224
+ This has the effect of providing a default title, but one that can be
225
+ overridden by any calling content component. The component would simply
226
+ define its own <tt>title</tt> method, and that method would then override
227
+ the default method provided by the container.
228
+
229
+ ==== Digression
230
+
231
+ This is a powerful construct that was shamelessly poached from HTML::Mason.
232
+ The design of Bijou attempts to address some of the issues of initialization
233
+ order present in Mason. In particular, the <tt><%init></tt> section is called
234
+ for all related (that is, existing in the same content/container chain)
235
+ components prior to invoking any such methods. This allows values to be
236
+ sourced from, for example, a database connection in the content component,
237
+ and to have such values be useable from the container. This is not possible
238
+ when using autohandlers in Mason, unless values are sourced from a
239
+ <tt><%shared></tt> section. Unfortunately, there is no <tt><%cleanup></tt>
240
+ equivalent for <tt><%shared></tt> sections in Mason.
241
+
242
+ === Initializer
243
+ *Syntax*: <%init> <b>...</b> </%init>
244
+
245
+ The initializer is a special method that gets invoked prior to the render
246
+ phase. Its content is evaluated as normal Ruby code. All initializers in
247
+ a content/container chain are invoked prior to the content render phase.
248
+ Any subordinate components (and any associated containers) called from
249
+ within the content section will have their initializers called at that time.
250
+
251
+ The args passed to the init section are the same as those for the main body.
252
+ Thus, to access a value from the args hash as a local variable or to provide
253
+ a default, an <tt><%args></tt> section must be specified. Any such declarations
254
+ cause a locally scoped variable having the specified name to be available both
255
+ in the init section and to the main body. Because these are implemented as
256
+ separate methods internally, they are separate variables. This implies that
257
+ any changes made to them in the init section might not be reflected in the
258
+ main body.
259
+
260
+ This discrepancy may or may not be seen as a benefit. It is one of the
261
+ outstanding issues left to be resolved. <b>NOTE: This behavior may change
262
+ in the future.</b> If a parameter's value is modified and the state needs
263
+ to be persisted for the render, just use a member variable to hold the value.
264
+
265
+ Note that an initializer is not the same a a Ruby constructor
266
+ (<tt>def initialze</tt>). A component's initialize method may be called at
267
+ any time, but the initializer will be called in a specific order, with the
268
+ expected arguments.
269
+
270
+ === Finalizer
271
+ *Syntax*: <%fini> <b>...</b> </%fini>
272
+
273
+ The finalizer is a special method that gets invoked after the render phase.
274
+ Its content is evaluated as normal Ruby code. It is useful for freeing
275
+ resources, such as database handles.
276
+
277
+ === Argument Block
278
+ *Syntax*: <%args> <b>...</b> </%args>
279
+
280
+ Argument blocks may be declared within methods or at the top level. They
281
+ have the following form.
282
+
283
+ <%args>
284
+ argument1 [ => value1 ] # comment
285
+ argument2 [ => value2 ]
286
+ ...
287
+ </%args>
288
+
289
+ The optional value, if specified, defines a default value that will be
290
+ assigned to the argument if one is not passed by the caller. If no value
291
+ is specified, then that argument is expected and will raise an exception
292
+ if it is not present in a caller's argument list. The value may contain
293
+ any single-line expression that is valid within the scope of the method.
294
+
295
+ === Code lines
296
+
297
+ We are considering <tt>%</tt> code lines as alternative to <tt><%</tt> code
298
+ blocks. This format, which is used by Mason, allows the user to define a
299
+ single-line section of code by prefixing it with a <tt>%</tt> token. The
300
+ token must appear in the first column of text. This format is conceptually
301
+ similar to single-line comments.
302
+
303
+ == Author
304
+
305
+ Author:: Todd Lucas <tl@dogandponyshow.org>
306
+ Requires:: Ruby 1.8.4 or later
307
+ License:: Copyright (c) 2007-2008 Todd Lucas.
308
+ Released under the same license as Ruby.
309
+
310
+ == Warranty
311
+
312
+ This software is provided "as is" and without any express or implied
313
+ warranties, including, without limitation, the implied warranties of
314
+ merchantibility and fitness for a particular purpose.
@@ -0,0 +1,60 @@
1
+
2
+ = Bijou 0.1.0 Released
3
+
4
+ == Changes
5
+
6
+ Version 0.1.0 is an initial alpha release. It is a demonstration of the basic
7
+ functionality of all core features, using simple interfaces: cgi, WEBrick, and
8
+ the standard I/O console.
9
+
10
+ * Initial alpha release, version 0.1.0
11
+
12
+ === Roadmap
13
+
14
+ * One of the first goals after the initial release is to add support for
15
+ one or more performant web servers. This means something like FastCGI,
16
+ SCGI, Mongrel, and/or Thin.
17
+
18
+ * Another consideration is replacing the hand-coded parser. The most
19
+ likely candidate is ANTLR with a Ruby target.
20
+
21
+ * Support for plugins. Much of this is TBD based on how people begin using
22
+ Bijou. One of the first targets will be filters. Filters are built-in
23
+ currently.
24
+
25
+ * Support code lines with a '%' prefix in the first column (a la Mason), as
26
+ an alternative to '<%' inline code segments. This format allows the user
27
+ to define a single-line section of code by prefixing it with a <tt>%</tt>
28
+ token. The token must appear in the first column of text. This format is
29
+ conceptually similar to single-line comments.
30
+
31
+ === Feedback
32
+
33
+ This initial release is intended for people to be able to test the waters.
34
+ Although I'm happy with the initial state of the project, there are some
35
+ things that will probably change. As such, this is not a production release
36
+ and the next release is likely to introduce breaking changes--though I
37
+ expect them to be minor.
38
+
39
+ Feedback is welcome on the project forum or via email, as are bug reports.
40
+
41
+ == What is Bijou?
42
+
43
+ Bijou is a templating system for Ruby. It was inspired by Perl's HTML::Mason.
44
+ Bijou files are text or HTML files that support in-line Ruby. Bijou also
45
+ supports the inclusion of text and code from other sources, called methods
46
+ and components. Components may be shared between files. They may also be used
47
+ as containers (sometimes called templates or layouts in other environments).
48
+ By chaining together components and containers, an arbitrarily sophisticated
49
+ system may be developed.
50
+
51
+ == Availability
52
+
53
+ You may install as a Ruby Gem using the following command
54
+
55
+ gem install bijou
56
+
57
+ or from the RubyForge pages
58
+
59
+ Home Page:: http://bijou.rubyforge.org
60
+ Download:: http://rubyforge.org/project/showfiles.php?group_id=4980
@@ -0,0 +1,34 @@
1
+
2
+ $:.push '../../lib'
3
+
4
+ require 'bijou'
5
+
6
+ parser = Bijou::Parser.new
7
+
8
+ class_name = "BirthdayView"
9
+
10
+ class_text = parser.parse(class_name, <<EOS)
11
+ <%args>
12
+ name => 'to whom it may concern'
13
+ </%args>
14
+
15
+ Dear <%= name %>,
16
+ I\'m writing this letter today to send my best wishes for a happy birthday.
17
+
18
+ Sincerely,
19
+ Your boss
20
+
21
+ ---- cut here ----
22
+ EOS
23
+
24
+ people = [ 'David', 'Tiffany', 'Richard' ]
25
+
26
+ people.each { |who|
27
+ args = { 'name' => who }
28
+
29
+ context = Bijou::Context.new(Bijou::Config.new)
30
+
31
+ letter = Bijou::Processor.execute(context, class_text, class_name, args)
32
+
33
+ print letter
34
+ }
@@ -0,0 +1,61 @@
1
+
2
+ $:.push '../../lib'
3
+
4
+ require 'bijou'
5
+
6
+ parser = Bijou::Parser.new
7
+
8
+ class_name = "HolidayView"
9
+
10
+ class_text = parser.parse(class_name, <<EOS)
11
+ <%! container='letterhead.txt' %>
12
+ <%args>
13
+ name => 'to whom it may concern'
14
+ </%args>
15
+
16
+ Dear <%= name %>,
17
+ In this holiday season, I\'d like to extend my personal best to you and yours.
18
+
19
+ <& signature.txt, signed => 'Your boss' &>
20
+
21
+ ---- cut here ----
22
+ EOS
23
+
24
+ def container_callback(context, path)
25
+ parser = Bijou::Parser.new
26
+
27
+ class_name = 'LetterView'
28
+ class_text = ''
29
+
30
+ File.open(path) do |file|
31
+ class_text = parser.parse(class_name, file, path)
32
+ end
33
+
34
+ Bijou::Processor.create_component(context, class_text, class_name)
35
+ end
36
+
37
+ def component_callback(context, path, args)
38
+ parser = Bijou::Parser.new
39
+
40
+ class_name = 'SignatureView'
41
+ class_text = ''
42
+
43
+ File.open(path) do |file|
44
+ class_text = parser.parse(class_name, file, path)
45
+ end
46
+
47
+ Bijou::Processor.execute(context, class_text, class_name, args)
48
+ end
49
+
50
+ people = [ 'David', 'Tiffany', 'Richard' ]
51
+
52
+ people.each { |who|
53
+ args = { 'name' => who }
54
+
55
+ context = Bijou::Context.new(Bijou::Config.new)
56
+
57
+ context.container_callback = method(:container_callback)
58
+ context.component_callback = method(:component_callback)
59
+
60
+ print Bijou::Processor.execute(context, class_text, class_name, args)
61
+ }