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
@@ -0,0 +1,201 @@
1
+
2
+ require 'cgi'
3
+ require 'bijou/processor'
4
+ require 'bijou/httpresponse'
5
+ require 'bijou/cgi/request'
6
+
7
+ module Bijou
8
+ #
9
+ # This module allows Bijou to run under CGI. It has only been tested under
10
+ # Apache.
11
+ #
12
+ module CGI
13
+ #
14
+ # This adapter encapsulates the differences between the CGI and the
15
+ # interfaces expected within the Bijou environment.
16
+ #
17
+ class Bijou::CGI::Adapter
18
+ def self.handle
19
+ t0 = Time.now
20
+
21
+ # Use binmode so CR\LF pairs aren't translated on Windows.
22
+ $stdout.binmode if defined? $stdout.binmode
23
+
24
+ #
25
+ # Initialize the configuration.
26
+ #
27
+
28
+ document_root = ENV['DOCUMENT_ROOT']
29
+
30
+ # The document root must be specified.
31
+ if !FileTest.directory?(document_root)
32
+ return self::error("The document root is invalid. " +
33
+ "Please check the CGI configuration.")
34
+ end
35
+
36
+ path_info = ENV['PATH_INFO']
37
+ bijou_cache = ENV['BIJOU_CACHE']
38
+ bijou_config = ENV['BIJOU_CONFIG']
39
+
40
+ if bijou_config
41
+ begin
42
+ config = Bijou::Config.load_file(bijou_config)
43
+ rescue SyntaxError
44
+ error = $!.to_s
45
+ error << "\nStack: " + $@.join("\n")
46
+
47
+ return self::diagnostic("Error loading configuration.", error)
48
+ end
49
+
50
+ if (!config)
51
+ return self::error("The configuration file path is invalid. " +
52
+ "Please check the CGI configuration.")
53
+ end
54
+ else
55
+ config = Bijou::Config.new
56
+ end
57
+
58
+ # The CGI value is always used for the document root because the
59
+ # server may have expectations about it.
60
+ config.document_root = document_root
61
+
62
+ # The config file overrides the CGI cache root value
63
+ if !config.cache_root && bijou_cache
64
+ config.cache_root = bijou_cache
65
+ end
66
+
67
+ config.includes.each do |inc|
68
+ $:.push inc
69
+ end
70
+
71
+ #
72
+ # Load the requested page.
73
+ #
74
+
75
+ processor = Bijou::Processor.new
76
+
77
+ # Build the page from the request.
78
+ begin
79
+ context = processor.load(path_info, config)
80
+ rescue Exception
81
+ msg = Bijou::ErrorFormatter.format_error :html, 4
82
+ return self.formatted_error("Error loading page", msg)
83
+ end
84
+
85
+ #
86
+ # Prepare the request data.
87
+ #
88
+
89
+ context.request = Bijou::CGI::Request.new(true)
90
+ context.response = HttpResponse.new
91
+
92
+ args = {}
93
+ args.replace(context.request.params);
94
+
95
+ #
96
+ # Handle the request.
97
+ #
98
+
99
+ begin
100
+ context.render(args)
101
+ rescue EndRequest
102
+ # Normal end request; possibly a redirect.
103
+ rescue Exception
104
+ msg = Bijou::ErrorFormatter.format_error :html, 4, context
105
+ return self.formatted_error("Error rendering page", msg)
106
+ end
107
+
108
+ #
109
+ # Return the response.
110
+ #
111
+
112
+ # print "Content-Type: text/html; charset=iso-8859-1\r\n\r\n"
113
+ print context.response.render_headers
114
+
115
+ if !context.response.suppress_content
116
+ puts context.output
117
+
118
+ if config.debug
119
+ t1 = Time.now
120
+
121
+ # self.print_request(context)
122
+ # self.print_environment
123
+
124
+ puts "<pre>" + "Time: #{t1 - t0}"
125
+ puts "Log:"
126
+ puts ::CGI.escapeHTML(context.get_log)
127
+ puts "Trace:"
128
+ puts ::CGI.escapeHTML(context.get_trace)
129
+ puts "</pre>"
130
+ end
131
+ end
132
+ end
133
+
134
+ def self.error(message)
135
+ print "Content-Type: text/html; charset=iso-8859-1\r\n\r\n"
136
+
137
+ puts '<html><h1>500 Internal server error</h1>' +
138
+ "<p>#{message}</p>" +
139
+ '</html>'
140
+ return nil
141
+ end
142
+
143
+ def self.diagnostic(message, diagnostic)
144
+ print "Content-Type: text/html; charset=iso-8859-1\r\n\r\n"
145
+
146
+ puts '<html><h1>500 Internal server error</h1>' +
147
+ "<h3>#{message}</h3>" +
148
+ "<pre>#{::CGI::escapeHTML(diagnostic)}</pre>" +
149
+ '</html>'
150
+ return nil
151
+ end
152
+
153
+ def self.formatted_error(title, message)
154
+ print "Content-Type: text/html; charset=iso-8859-1\r\n\r\n"
155
+ puts '<html>'
156
+ puts '<head><title>Bijou Error</title>'
157
+ puts '<style type="text/css">'
158
+ puts Bijou::ErrorFormatterHTML.style
159
+ puts '</style>'
160
+ puts '</head>'
161
+ puts '<body>'
162
+ puts "<h1>#{title}</h1>"
163
+ puts message
164
+ puts '</body>'
165
+ puts '</html>'
166
+ return nil
167
+ end
168
+
169
+ def self.print_environment()
170
+ # print "Content-Type: text/html; charset=iso-8859-1\r\n\r\n"
171
+ # print "Hello, world!"
172
+ # puts $:
173
+
174
+ print "<pre>" +
175
+ ::CGI::escapeHTML(
176
+ ENV.collect() do |key, value|
177
+ key + " --> " + value + "\n"
178
+ end.join("")
179
+ ) +
180
+ "</pre>"
181
+ end
182
+
183
+ def self.print_request(context)
184
+ # print "Content-Type: text/html; charset=iso-8859-1\r\n\r\n"
185
+ # print "Hello, world!"
186
+ # puts $:
187
+
188
+ cgi = context.request.cgi
189
+
190
+ print "<pre>" +
191
+ ::CGI::escapeHTML(
192
+ "query: " + cgi.query_string.inspect + "\n" +
193
+ "form: " + cgi.form.inspect + "\n" +
194
+ "cookies: " + cgi.cookies.inspect + "\n" +
195
+ "params: " + cgi.params.inspect + "\n"
196
+ ) +
197
+ "</pre>"
198
+ end
199
+ end
200
+ end
201
+ end
@@ -0,0 +1,5 @@
1
+
2
+ require 'cgi'
3
+ require 'bijou/cgi/adapter'
4
+
5
+ Bijou::CGI::Adapter.handle
@@ -0,0 +1,37 @@
1
+
2
+ require 'bijou/minicgi'
3
+ require 'bijou/httprequest'
4
+
5
+ module Bijou
6
+ module CGI
7
+ #
8
+ # The request object adapts the CGI environment to a standardized
9
+ # Bijou interface. The normal Ruby cgi class is not used in this
10
+ # case. The Bijou::MiniCGI class adapts some of the useful functionality
11
+ # provided by the normal cgi class for use from the request object.
12
+ #
13
+ class Request < Bijou::HttpRequest
14
+
15
+ #
16
+ # Set single to true to have request parameters with single values
17
+ # be converted from an array to a single value. Otherwise, all parameter
18
+ # values will be arrays.
19
+ #
20
+ def initialize(single=true)
21
+ super()
22
+
23
+ @cgi = Bijou::MiniCGI.new(single)
24
+
25
+ @params = @cgi.params
26
+ @query_string = @cgi.get
27
+ @form = @cgi.post
28
+ @cookies = @cgi.cookies
29
+ @server_variables = @cgi.server
30
+ @http_method = @cgi.method
31
+ end
32
+
33
+ attr_reader :cgi
34
+
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,12 @@
1
+ #
2
+ # Copyright (c) 2007-2008 Todd Lucas. All rights reserved.
3
+ #
4
+ # common.rb - Shared declarations
5
+ #
6
+
7
+ #
8
+ # The Bijou module contains all related classes to help keep the global
9
+ # namespace clean.
10
+ #
11
+ module Bijou
12
+ end
@@ -0,0 +1,108 @@
1
+ #
2
+ # Copyright (c) 2007-2008 Todd Lucas. All rights reserved.
3
+ #
4
+ # component.rb - The base class of all Bijou runtime components.
5
+ #
6
+ require 'bijou/common'
7
+ require 'bijou/filters'
8
+ require 'bijou/context'
9
+
10
+ module Bijou
11
+ #
12
+ # The Component class is used to represent Bijou pages, components, and
13
+ # containers. It is the default base class used during the code generation
14
+ # phase.
15
+ #
16
+ # A component may use the <tt>base</tt> directive to specify an alternative
17
+ # class. This can be done to provide helper functions to a page or to
18
+ # override certain methods, for example. Any custom base class should
19
+ # derive from Bijou::Component. The file implementing the class will also
20
+ # need to be part of the require_list array in Bijou::Config.
21
+ #
22
+ class Component
23
+ alias raw_puts puts
24
+ alias raw_print print
25
+ alias raw_printf printf
26
+
27
+ attr_reader :context
28
+
29
+ # If the <%! container %> directive is used, the derived class will
30
+ # return a physical path to the containing file.
31
+ def self.container
32
+ nil
33
+ end
34
+
35
+ # Used for meaningful stack frames in errors (to work around an eval
36
+ # shortcoming).
37
+ def self.source_filename
38
+ nil
39
+ end
40
+
41
+ # Used for meaningful stack frames in errors (to work around an eval
42
+ # shortcoming).
43
+ def self.cache_filename
44
+ nil
45
+ end
46
+
47
+ def initialize(context)
48
+ @context = context
49
+ end
50
+
51
+ # The backing method for the %init block.
52
+ def init(args)
53
+ end
54
+
55
+ # The backing method for the %fini block.
56
+ def fini
57
+ end
58
+
59
+ # A synonym for Context#sinvoke.
60
+ def sinvoke(name, args={})
61
+ @context.sinvoke(name, args)
62
+ end
63
+
64
+ # A synonym for Context#invoke.
65
+ def invoke(name, args={})
66
+ @context.invoke(name, args)
67
+ end
68
+
69
+ # Behaves similarly to IO#puts, except the output is rendered to the
70
+ # response stream.
71
+ def puts(*args)
72
+ @context.writeline(args.join("\n"))
73
+ end
74
+
75
+ # Behaves similarly to IO#print, except the output is rendered to the
76
+ # response stream.
77
+ def print(*args)
78
+ sep = ''
79
+ term = ''
80
+
81
+ if $,
82
+ sep = $,
83
+ end
84
+
85
+ if $\
86
+ term = $\
87
+ end
88
+
89
+ @context.write(args.join(sep) + term)
90
+ end
91
+
92
+ # Behaves similarly to IO#printf, except the output is rendered to the
93
+ # response stream.
94
+ def printf(format, *args)
95
+ @context.write(sprintf(format, *args))
96
+ end
97
+
98
+ # A synonym for Context#request.
99
+ def request
100
+ @context.request
101
+ end
102
+
103
+ # A synonym for Context#response.
104
+ def response
105
+ @context.response
106
+ end
107
+ end
108
+ end
@@ -0,0 +1,60 @@
1
+ #
2
+ # Copyright (c) 2007-2008 Todd Lucas. All rights reserved.
3
+ #
4
+ # config.rb - Encapsulates the loaded configuration.
5
+ #
6
+ require 'bijou/common'
7
+
8
+ module Bijou
9
+ class Log
10
+ None = 0
11
+ Error = 1
12
+ Warn = 2
13
+ Info = 3
14
+ end
15
+
16
+ class Config
17
+ def initialize
18
+ @file_path = nil
19
+
20
+ @document_root = nil
21
+ @cache_root = nil
22
+ @cache_ext = '.obj'
23
+ @includes = []
24
+
25
+ @component_base = nil
26
+ @require_list = nil
27
+
28
+ @cache = true
29
+ @debug = false
30
+ @trace_level = Bijou::Log::None
31
+ @trace_buffer = true
32
+ end
33
+
34
+ attr_accessor :file_path
35
+
36
+ attr_accessor :document_root
37
+ attr_accessor :cache_root
38
+ attr_accessor :cache_ext
39
+ attr_accessor :includes
40
+
41
+ attr_accessor :component_base
42
+ attr_accessor :require_list
43
+
44
+ attr_accessor :cache
45
+ attr_accessor :debug
46
+ attr_accessor :trace_level
47
+ attr_accessor :trace_buffer
48
+
49
+ def self.load_file(file_path)
50
+ if file_path && !file_path.empty?
51
+ f = File.open(file_path, "r")
52
+ cfg = new
53
+ cfg.instance_eval(f.read(), file_path)
54
+ cfg.file_path = file_path
55
+ return cfg
56
+ end
57
+ nil
58
+ end
59
+ end
60
+ end
@@ -0,0 +1,167 @@
1
+
2
+ require 'getoptlong'
3
+ require 'bijou/processor'
4
+ require 'bijou/httpresponse'
5
+ require 'bijou/console/request'
6
+
7
+ module Bijou
8
+ #
9
+ # This module allows Bijou to be invoked from the command-line using
10
+ # stdin and stdout.
11
+ #
12
+ module Console
13
+ #
14
+ # This adapter sets up an approximation of a web server environment,
15
+ # so that Bijou can be run from the command line. This permits simple
16
+ # testing and experimentation. It also allows for the use of certain
17
+ # debugging tools and techniques that would otherwise not be available.
18
+ #
19
+ class Bijou::Console::Adapter
20
+ def self.handle
21
+ opts = GetoptLong.new(
22
+ [ "--config" , "-c", GetoptLong::OPTIONAL_ARGUMENT ],
23
+ [ "--query", "-q", GetoptLong::REQUIRED_ARGUMENT ],
24
+ [ "--help", "-h", "-?", GetoptLong::NO_ARGUMENT ]
25
+ )
26
+
27
+ debug = false
28
+ t0 = Time.now
29
+
30
+ document_root = ENV['DOCUMENT_ROOT']
31
+
32
+ path_info = ENV['PATH_INFO']
33
+ bijou_cache = ENV['BIJOU_CACHE']
34
+ bijou_config = ENV['BIJOU_CONFIG']
35
+
36
+ query_string = ''
37
+
38
+ # process the parsed options
39
+ opts.each do |opt, arg|
40
+ case opt
41
+ when '--config'
42
+ bijou_config = arg
43
+ when '--query'
44
+ query_string = arg
45
+ when '--help'
46
+ return usage()
47
+ end
48
+ end
49
+
50
+ if ARGV.length == 1
51
+ path_info = ARGV[0]
52
+ elsif !document_root
53
+ puts "Missing document argument (try --help)"
54
+ return 0
55
+ end
56
+
57
+ if bijou_config
58
+ begin
59
+ config = Bijou::Config.load_file(bijou_config)
60
+ rescue SyntaxError
61
+ error = $!.to_s
62
+ error << "\nStack: " + $@.join("\n")
63
+
64
+ return self::diagnostic("Error loading configuration.", error)
65
+ end
66
+
67
+ if (!config)
68
+ return self::error("The configuration file path is invalid.")
69
+ end
70
+ else
71
+ config = Bijou::Config.new
72
+ end
73
+
74
+ # The config file overrides the environment settings.
75
+ if !config.document_root || config.document_root.empty?
76
+ if document_root
77
+ config.document_root = document_root
78
+ else
79
+ config.document_root = Dir.getwd
80
+ end
81
+ end
82
+
83
+ if !config.cache_root && bijou_cache
84
+ config.cache_root = bijou_cache
85
+ end
86
+
87
+ # The config file overrides the environment cache root value
88
+ if !config.cache_root && bijou_cache
89
+ config.cache_root = bijou_cache
90
+ end
91
+
92
+ # No need to defer trace render when outside of an HTTP environment.
93
+ config.trace_buffer = false
94
+
95
+ config.includes.each do |inc|
96
+ $:.push inc
97
+ end
98
+
99
+ processor = Bijou::Processor.new
100
+
101
+ # Build the page from the request.
102
+ begin
103
+ context = processor.load(path_info, config)
104
+ rescue Exception
105
+ msg = Bijou::ErrorFormatter.format_error :text, 4, context
106
+ return self::diagnostic("Error loading page", msg)
107
+ end
108
+
109
+ #
110
+ # Prepare the request data.
111
+ #
112
+
113
+ context.request = Bijou::Console::Request.new(query_string)
114
+ context.response = Bijou::HttpResponse.new
115
+
116
+ args = {}
117
+ args.replace(context.request.params);
118
+
119
+ # Render the result of executing the page.
120
+ begin
121
+ context.render(args)
122
+ rescue Exception
123
+ msg = Bijou::ErrorFormatter.format_error :text, 4, context
124
+ return self::diagnostic("Syntax error loading page", msg)
125
+ end
126
+
127
+ puts context.output;
128
+
129
+ t3 = Time.now
130
+
131
+ if debug
132
+ puts context.get_log
133
+
134
+ if config.trace_level > 0
135
+ # print_environment
136
+ puts context.get_trace
137
+ end
138
+ end
139
+
140
+ end
141
+
142
+ def self.error(message)
143
+ puts "error: #{message}"
144
+ return nil
145
+ end
146
+
147
+ def self.diagnostic(message, diagnostic)
148
+ puts "#{message}:\n#{diagnostic}"
149
+ return nil
150
+ end
151
+
152
+ def self.print_environment()
153
+ print ENV.collect() do |key, value|
154
+ key + " --> " + value + "\n"
155
+ end.join("")
156
+ end
157
+
158
+ def self.usage()
159
+ puts "Renders a Bijou console to stdout.\n\n"
160
+ puts "#{File.basename($0)} filename\n\n"
161
+ puts " -h, --help This help message"
162
+ puts " -c, --config file Specify a config file"
163
+ puts ' -q, --query args Pass query string arguments (e.g, "a=1&b=2")'
164
+ end
165
+ end
166
+ end
167
+ end