bijou 0.1.0

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