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
@@ -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