bahuvrihi-tap 0.11.1 → 0.11.2

Sign up to get free protection for your applications and to get access to all the features.
data/cmd/server.rb ADDED
@@ -0,0 +1,42 @@
1
+ # tap server {options}
2
+ #
3
+ # Initializes a tap server.
4
+
5
+ require 'tap'
6
+ require 'tap/support/gems/rack'
7
+
8
+ env = Tap::Env.instance
9
+
10
+ #
11
+ # handle options
12
+ #
13
+ options = {:Port => 8080}
14
+ OptionParser.new do |opts|
15
+
16
+ opts.separator ""
17
+ opts.separator "options:"
18
+
19
+ opts.on("-h", "--help", "Show this message") do
20
+ opts.banner = Tap::Support::TDoc.usage(__FILE__)
21
+ puts opts
22
+ exit
23
+ end
24
+
25
+ opts.on("-p", "--port PORT", Integer, "Specifies the port (default #{options[:Port]})") do |value|
26
+ options[:Port] = value
27
+ end
28
+
29
+ opts.on("-d", "--development", Integer, "Specifies development mode") do
30
+ env.config[:development] = true
31
+ end
32
+
33
+ end.parse!(ARGV)
34
+
35
+ #
36
+ # cgi dir and public dir can be set in tap.yml
37
+ #
38
+
39
+ env.extend Tap::Support::Gems::Rack
40
+ Rack::Handler::WEBrick.run(env, options) do |handler|
41
+ env.handler = handler
42
+ end
data/lib/tap/constants.rb CHANGED
@@ -1,7 +1,7 @@
1
1
  module Tap
2
2
  MAJOR = 0
3
3
  MINOR = 11
4
- TINY = 1
4
+ TINY = 2
5
5
 
6
6
  VERSION="#{MAJOR}.#{MINOR}.#{TINY}"
7
7
  WEBSITE="http://tap.rubyforge.org"
data/lib/tap/spec.rb ADDED
@@ -0,0 +1,39 @@
1
+ $:.unshift File.expand_path("#{File.dirname(__FILE__)}/..")
2
+ require 'tap/test/extensions'
3
+
4
+ require 'rubygems'
5
+ require 'minitest/spec'
6
+
7
+ class MiniTest::Unit::TestCase
8
+ extend Tap::Test::Extensions
9
+
10
+ class << self
11
+ # Causes a test suite to be skipped. If a message is given, it will
12
+ # print and notify the user the test suite has been skipped.
13
+ def skip_test(msg=nil)
14
+ @@test_suites.delete(self)
15
+ puts "Skipping #{self}#{msg.empty? ? '' : ': ' + msg}"
16
+ end
17
+
18
+ private
19
+
20
+ # Infers the test root directory from the calling file.
21
+ # 'some_class.rb' => 'some_class'
22
+ # 'some_class_test.rb' => 'some_class'
23
+ def test_root_dir # :nodoc:
24
+ # caller[1] is considered the calling file (which should be the test case)
25
+ # note that caller entries are like this:
26
+ # ./path/to/file.rb:10
27
+ # ./path/to/file.rb:10:in 'method'
28
+
29
+ calling_file = caller[1].gsub(/:\d+(:in .*)?$/, "")
30
+ calling_file.chomp(File.extname(calling_file)).chomp("_spec")
31
+ end
32
+ end
33
+
34
+ def method_name
35
+ @method_name ||= name.gsub(/\s/, "_").gsub(/^test_/, "")
36
+ end
37
+ end
38
+
39
+ MiniTest::Unit.autorun
@@ -1,6 +1,6 @@
1
1
  require 'tap/support/class_configuration'
2
2
  require 'tap/support/validation'
3
- require 'tap/support/lazy_attributes'
3
+ require 'tap/support/lazydoc/attributes'
4
4
  require 'tap/support/lazydoc/config'
5
5
 
6
6
  module Tap
@@ -23,7 +23,7 @@ module Tap
23
23
  # c.respond_to?('one=') # => true
24
24
  #
25
25
  module ConfigurableClass
26
- include Tap::Support::LazyAttributes
26
+ include Lazydoc::Attributes
27
27
 
28
28
  # A ClassConfiguration holding the class configurations.
29
29
  attr_reader :configurations
@@ -0,0 +1,279 @@
1
+ require 'rack'
2
+ require 'yaml'
3
+
4
+ # in a future release, it looks like this will be changed
5
+ require 'rack/file'
6
+ #require 'rack/mime'
7
+
8
+ module Tap
9
+ module Support
10
+ module Gems
11
+
12
+ Tap::Env.manifest(:cgis) do |env|
13
+ entries = env.root.glob(:cgi, "**/*.rb").sort_by {|path| File.basename(path) }
14
+ Support::Manifest.intern(entries) do |manifest, path|
15
+ "/" + manifest.env.root.relative_filepath(:cgi, path)
16
+ end
17
+ end
18
+
19
+ # = UNDER CONSTRUCTION
20
+ # Support for a Tap::Server, built on {Rack}[http://rack.rubyforge.org/].
21
+ #
22
+ # Tap::Support::Gems::Rack is intended to extend a Tap::Env
23
+ module Rack
24
+
25
+ # The handler for the server (ex Rack::Handler::WEBrick)
26
+ attr_accessor :handler
27
+
28
+ # The default error template used by response
29
+ # when an error occurs.
30
+ DEFAULT_ERROR_TEMPLATE = %Q{
31
+ <html>
32
+ <body>
33
+ # Error handling request: <%= error.message %></br>
34
+ # <%= error.backtrace.join("<br/># ") %>
35
+
36
+ <code><pre>
37
+ <%= cgi.to_yaml %>
38
+ <%= rack.to_yaml %>
39
+ </pre></code>
40
+ </body>
41
+ </html>
42
+ }
43
+
44
+ # Creates a [status, headers, body] response using the result of the
45
+ # block as the body. The status and headers the defaults for
46
+ # {Rack::Response}[http://rack.rubyforge.org/doc/classes/Rack/Response.html].
47
+ # If an error occurs, a default error message is generated using the
48
+ # DEFAULT_ERROR_TEMPLATE.
49
+ def response(rack_env)
50
+ ::Rack::Response.new.finish do |res|
51
+ res.write begin
52
+ yield(res)
53
+ rescue
54
+ template(DEFAULT_ERROR_TEMPLATE, env_attrs(rack_env).merge(:error => $!))
55
+ end
56
+ end
57
+ end
58
+
59
+ # The {Rack}[http://rack.rubyforge.org/doc/] interface method. Call
60
+ # routesrequests (with preference) to:
61
+ # * static pages
62
+ # * cgi scripts
63
+ # * default responses
64
+ #
65
+ # === Static pages
66
+ # Static pages may be served from any env in self. A static page is
67
+ # served if a file with the request path exists under the 'public'
68
+ # directory for any env.
69
+ #
70
+ # Envs are searched in order, using the Env#search_path method.
71
+ #
72
+ # === CGI scripts
73
+ # Like static pages, cgi scripts may be served from any env in self.
74
+ # Scripts are discovered using a search of the cgi manifest. See
75
+ # cgi_response for more details.
76
+ #
77
+ # === Default responses
78
+ # The default response is path-dependent:
79
+ #
80
+ # path action
81
+ # /, /index render the manifest.
82
+ # all others render a 404 response
83
+ #
84
+ # The manifest may be refreshed by setting a query string:
85
+ #
86
+ # /?refresh=true
87
+ # /index?refresh=true
88
+ #
89
+ def call(rack_env)
90
+ path = rack_env['PATH_INFO']
91
+
92
+ case
93
+ when static_path = search_path(:public, path) {|file| File.file?(file) }
94
+ # serve named static pages
95
+ file_response(static_path, rack_env)
96
+
97
+ when cgi_path = cgis.search(path)
98
+ # serve cgis
99
+ cgi_response(cgi_path, rack_env)
100
+
101
+ # when task_path = search(:tasks, path)
102
+ # # serve tasks
103
+ # cgi_response('task', rack_env)
104
+
105
+ when path == "/" || path == "/index"
106
+ # serve up the homepage
107
+ if rack_env["QUERY_STRING"] == "refresh=true"
108
+ # reset(:cgis) do |key, path|
109
+ # Support::Lazydoc[path].resolved = false
110
+ # end
111
+ end
112
+ render_response('index.erb', rack_env)
113
+
114
+ else
115
+ # handle all other requests as errors
116
+ render_response('404.erb', rack_env)
117
+
118
+ end
119
+ end
120
+
121
+ # Generates a [status, headers, body] response for the specified file.
122
+ # Patterned after {Rack::File#._call}[http://rack.rubyforge.org/doc/classes/Rack/File.html].
123
+ def file_response(path, rack_env)
124
+ response(rack_env) do |res|
125
+ content = File.read(path)
126
+ res.headers.merge!(
127
+ "Last-Modified" => File.mtime(path).httpdate,
128
+ "Content-Type" => ::Rack::File::MIME_TYPES[File.extname(path)] || "text/plain", # Rack::Mime.mime_type(File.extname(path), 'text/plain'),
129
+ "Content-Length" => content.size.to_s)
130
+
131
+ content
132
+ end
133
+ end
134
+
135
+ # Generates a [status, headers, body] response for the specified cgi.
136
+ # The cgi will be run with ENV set as specified in rack_env.
137
+ def cgi_response(cgi_path, rack_env)
138
+
139
+ # setup standard ios for capture
140
+ current_input = $stdin
141
+ current_output = $stdout
142
+
143
+ cgi_input = rack_env['rack.input']
144
+ cgi_output = StringIO.new("")
145
+
146
+ begin
147
+ $stdin = cgi_input
148
+ $stdout = cgi_output
149
+
150
+ # run the cgi
151
+ with_ENV(rack_env) { load(cgi_path) }
152
+
153
+ # collect the headers and body from the output
154
+ headers, body = cgi_output.string.split(/\r?\n\r?\n/, 2)
155
+
156
+ raise "missing headers from: #{cgi_path}" if headers == nil
157
+ body = "" if body == nil
158
+
159
+ headers = headers.split(/\r?\n/).inject({}) do |hash, line|
160
+ key, value = line.split(/:/, 2)
161
+ hash[key] = value
162
+ hash
163
+ end
164
+
165
+ # generate the response
166
+ [headers.delete('Status') || 200, headers, body]
167
+
168
+ rescue(Exception)
169
+ # when an error occurs, return a standard cgi error with backtrace
170
+ [500, {'Content-Type' => 'text/plain'}, %Q{#{$!.class}: #{$!.message}\n#{$!.backtrace.join("\n")}}]
171
+
172
+ ensure
173
+ $stdin = current_input
174
+ $stdout = current_output
175
+ end
176
+ end
177
+
178
+ # def cgi_template(name, attributes={})
179
+ # path = root.filepath(:template, "#{name}.erb")
180
+ # Templater.new( File.read(path), {:server => self}.merge(attributes) ).build
181
+ # end
182
+
183
+ # Generates a [status, headers, body] response using the first existing
184
+ # template matching path (as determined by Env#search_path) and the
185
+ # specified rack_env.
186
+ def render_response(path, rack_env)
187
+ # partition and sort the env variables into
188
+ # cgi and rack variables.
189
+ rack, cgi = rack_env.to_a.partition do |(key, value)|
190
+ key =~ /^rack/
191
+ end.collect do |part|
192
+ part.sort_by do |key, value|
193
+ key
194
+ end.inject({}) do |hash, (key,value)|
195
+ hash[key] = value
196
+ hash
197
+ end
198
+ end
199
+
200
+ response(rack_env) do
201
+ render(path, env_attrs(rack_env))
202
+ end
203
+ end
204
+
205
+ module Render
206
+ def renderer(path)
207
+ template = env.search_path(:template, path) {|file| File.file?(file) }
208
+ raise("no such template: #{path}") if template == nil
209
+ Tap::Support::Templater.new(File.read(template), marshal_dump).extend(Render)
210
+ end
211
+
212
+ def render(path, attrs={})
213
+ renderer(path).build(attrs)
214
+ end
215
+ end
216
+
217
+ # Builds the specified template using the rack_env and additional
218
+ # attributes. The rack_env is partitioned into rack-related and
219
+ # cgi-related hashes (all rack_env entries where the key starts
220
+ # with 'rack' are rack-related, the others are cgi-related).
221
+ #
222
+ # The template is built with the following standard locals:
223
+ #
224
+ # server self
225
+ # cgi the cgi-related hash
226
+ # rack the rack-related hash
227
+ #
228
+ # Plus the attributes.
229
+ def render(path, attributes={}) # :nodoc:
230
+ path = search_path(:template, path) {|file| File.file?(file) }
231
+ raise("no such template: #{path}") if path == nil
232
+
233
+ template(File.read(path) , attributes)
234
+ end
235
+
236
+ def env_attrs(rack_env)
237
+ # partition and sort the env variables into
238
+ # cgi and rack variables.
239
+ rack, cgi = rack_env.to_a.partition do |(key, value)|
240
+ key =~ /^rack/
241
+ end.collect do |part|
242
+ part.sort_by do |key, value|
243
+ key
244
+ end.inject({}) do |hash, (key,value)|
245
+ hash[key] = value
246
+ hash
247
+ end
248
+ end
249
+
250
+ {:env => self, :cgi => cgi, :rack => rack}
251
+ end
252
+
253
+ def template(template, attributes={}) # :nodoc:
254
+ Templater.new(template, attributes).extend(Render).build
255
+ end
256
+
257
+ protected
258
+
259
+ # Executes block with ENV set to the specified hash.
260
+ # Non-string values in hash are skipped.
261
+ def with_ENV(hash) # :nodoc:
262
+ current_env = {}
263
+ ENV.each_pair {|key, value| current_env[key] = value }
264
+
265
+ begin
266
+ ENV.clear
267
+ hash.each_pair {|key, value| ENV[key] = value if value.kind_of?(String)}
268
+
269
+ yield
270
+ ensure
271
+ ENV.clear
272
+ current_env.each_pair {|key, value| ENV[key] = value }
273
+ end
274
+ end
275
+
276
+ end
277
+ end
278
+ end
279
+ end
@@ -4,7 +4,7 @@ module Tap
4
4
  module Support
5
5
 
6
6
  # Lazydoc lazily pulls documentation out of source files and makes it
7
- # available through LazyAttributes. Lazydoc can find two types of
7
+ # available through Attributes. Lazydoc can find two types of
8
8
  # documentation, constant attributes and code comments. To illustrate,
9
9
  # consider the following:
10
10
  #
@@ -19,7 +19,7 @@ module Tap
19
19
  # # line, the next constant attribute,
20
20
  # # or an end key
21
21
  # class Sample
22
- # extend Tap::Support::LazyAttributes
22
+ # extend Tap::Support::Lazydoc::Attributes
23
23
  # self.source_file = __FILE__
24
24
  #
25
25
  # lazy_attr :key
@@ -0,0 +1,48 @@
1
+ require 'tap/support/lazydoc'
2
+
3
+ module Tap
4
+ module Support
5
+ module Lazydoc
6
+ # Attributes adds methods to declare class-level accessors
7
+ # for Lazydoc attributes. The source_file for the class must
8
+ # be set manually.
9
+ #
10
+ # # ConstName::key value
11
+ # class ConstName
12
+ # class << self
13
+ # include Lazydoc::Attributes
14
+ # end
15
+ #
16
+ # self.source_file = __FILE__
17
+ # lazy_attr :key
18
+ # end
19
+ #
20
+ # ConstName::key.subject # => 'value'
21
+ #
22
+ module Attributes
23
+
24
+ # The source_file for self. Must be set independently.
25
+ attr_accessor :source_file
26
+
27
+ # Returns the lazydoc for source_file
28
+ def lazydoc(resolve=true)
29
+ lazydoc = Lazydoc[source_file]
30
+ lazydoc.resolve if resolve
31
+ lazydoc
32
+ end
33
+
34
+ # Creates a lazy attribute accessor for the specified attribute.
35
+ def lazy_attr(key, attribute=key)
36
+ instance_eval %Q{
37
+ def #{key}
38
+ lazydoc[to_s]['#{attribute}'] ||= Lazydoc::Comment.new
39
+ end
40
+
41
+ def #{key}=(comment)
42
+ Lazydoc[source_file][to_s]['#{attribute}'] = comment
43
+ end}
44
+ end
45
+ end
46
+ end
47
+ end
48
+ end