htty-rack 0.0.5

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,4 @@
1
+ .bundle/
2
+ doc/
3
+ vendor/
4
+ *.gem
@@ -0,0 +1,9 @@
1
+ The MIT License
2
+
3
+ Source code for _htty-rack_ is copyright (c) 2010 Florian Gilcher[mailto:florian.gilcher@asquera.de].
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
6
+
7
+ The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
8
+
9
+ THE SOFTWARE IS PROVIDED "AS IS," WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,40 @@
1
+ _________________________
2
+ < no fancy ASCII art here >
3
+ -------------------------
4
+ \ ^__^
5
+ \ (oo)\_______
6
+ (__)\ )\/\
7
+ ||----w |
8
+ || ||
9
+
10
+ htty-rack[http://www.github.com/Asquera/htty-rack] is an extension to htty[http://htty.github.com] that switches the HTTP backend in favour of a Rack application. For that purpose, it also provides a set of commands for controlling which rack application is used etc.
11
+
12
+ = Warning
13
+
14
+ Alpha. No Features guaranteed.
15
+
16
+ = Installation
17
+
18
+ Use rubygems:
19
+
20
+ $ gem install htty-rack
21
+
22
+ = Usage
23
+
24
+ htty-rack uses a different executable than htty. Start htty-rack using:
25
+
26
+ $ htty-rack <config-file>
27
+
28
+ If no config (*.ru) file is given, htty-rack will recursively descend to find a file called "config.ru".
29
+
30
+ = Examples
31
+
32
+ Beyond the examples described on the htty[http://htty.github.com] page, htty-rack supports a few other commands:
33
+
34
+ * app <app> will change the rack appliation in use. The argument must be a ruby constant.
35
+ * config <file> will load a new rackup file and use the application therein.
36
+ * irb starts irb so that you can manipulate the environment.
37
+
38
+ = Thanks
39
+
40
+ * Nils Jonsson for writing htty and making this project possible
@@ -0,0 +1,11 @@
1
+ require 'rake/testtask'
2
+
3
+ Rake::TestTask.new("test") do |test|
4
+ test.libs << 'test'
5
+ test.pattern = 'test/**/*_test.rb'
6
+ test.warning = false
7
+ test.verbose = true
8
+ test.ruby_opts = ['-rubygems', '-rtest_helper']
9
+ end
10
+
11
+ task :default => [:test]
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.0.5
@@ -0,0 +1,7 @@
1
+ #!/usr/bin/env ruby
2
+ gem 'htty'
3
+ require 'htty'
4
+
5
+ require File.expand_path("#{File.dirname __FILE__}/../lib/htty/rack")
6
+
7
+ HTTY::Rack::CLI.new(ARGV).run!
@@ -0,0 +1 @@
1
+ run lambda {|env| [200,{"Content-Length" => "4"}, ["test"]]}
@@ -0,0 +1,18 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ Gem::Specification.new do |s|
4
+ s.name = "htty-rack"
5
+ s.version = File.read("VERSION")
6
+ s.platform = Gem::Platform::RUBY
7
+ s.authors = ["Florian Gilcher"]
8
+ s.email = ["florian.gilcher@asquera.de"]
9
+ s.homepage = "http://www.github.com/Asquera/htty-rack"
10
+ s.summary = "htty-rack is htty for rack applications"
11
+ s.description = "A CLI for rack applications based on htty."
12
+
13
+ s.add_dependency "htty", ">= 1.0.0"
14
+
15
+ s.files = `git ls-files`.split("\n")
16
+ s.executables = `git ls-files`.split("\n").map{|f| f =~ /^bin\/(.*)/ ? $1 : nil}.compact
17
+ s.require_path = 'lib'
18
+ end
@@ -0,0 +1,31 @@
1
+ Dir.glob "#{File.dirname __FILE__}/rack/*.rb" do |f|
2
+ require File.expand_path("#{File.dirname __FILE__}/rack/" +
3
+ File.basename(f, '.rb'))
4
+ end
5
+
6
+ require 'rack'
7
+ HTTY::CLI::Commands::Help.register_additional_category("Rack")
8
+ HTTY::CLI::Commands::Help.register_additional_category("Debug")
9
+
10
+ module HTTY
11
+ module Rack
12
+ VERSION = File.read("#{File.dirname __FILE__}/../../VERSION").chomp
13
+
14
+ def self.build_app(filename = nil)
15
+ config_file_name = File.basename(filename || find_config_file)
16
+ config_file = File.read(config_file_name)
17
+ app = ::Rack::Builder.new { instance_eval(config_file) }.to_app
18
+ [config_file_name, app]
19
+ end
20
+
21
+ def self.find_config_file
22
+ if Dir.glob("config.ru").length > 0
23
+ File.join(Dir.pwd,"config.ru")
24
+ elsif Dir.pwd != "/"
25
+ Dir.chdir("..") { find_config_file }
26
+ else
27
+ raise "Cannot find config.ru"
28
+ end
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,27 @@
1
+ module HTTY::Rack
2
+ class CLI < HTTY::CLI
3
+
4
+ attr_accessor :config_file_name
5
+
6
+ def initialize(command_line_arguments, session_class = HTTY::Rack::Session)
7
+ super
8
+ end
9
+
10
+ def prompt
11
+ last_request = session.requests.last
12
+ if last_request.app.respond_to? :name
13
+ display = last_request.app.name
14
+ else
15
+ display = last_request.app_file
16
+ end
17
+
18
+ strong(display + ":" +
19
+ session.requests.last.send(:path_query_and_fragment)) +
20
+ normal('> ')
21
+ end
22
+
23
+ def command_folders
24
+ super + ["#{File.dirname __FILE__}/commands"]
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,40 @@
1
+ class HTTY::CLI::Commands::App < HTTY::CLI::Command
2
+
3
+ # Returns the name of a category under which help for the _app_ command
4
+ # should appear.
5
+ def self.category
6
+ 'Rack'
7
+ end
8
+
9
+ # Returns the arguments for the command-line usage of the _app_ command.
10
+ def self.command_line_arguments
11
+ 'constant'
12
+ end
13
+
14
+ # Returns the help text for the _app_ command.
15
+ def self.help
16
+ 'Sets the active app'
17
+ end
18
+
19
+ # Returns the extended help text for the _app_ command.
20
+ def self.help_extended
21
+ 'Sets the app to the constant provided. The app must be required first.' +
22
+ 'This operation does not clear cookies.'
23
+ end
24
+
25
+ # Performs the _app_ command.
26
+ def perform
27
+ unless arguments.length == 1
28
+ raise ArgumentError,
29
+ "wrong number of arguments (#{arguments.length} for 1)"
30
+ end
31
+
32
+ app = Module.const_get(arguments.first)
33
+
34
+ add_request_if_has_response do |request|
35
+ request.app = app
36
+ request
37
+ end
38
+ end
39
+
40
+ end
@@ -0,0 +1,40 @@
1
+ class HTTY::CLI::Commands::Config < HTTY::CLI::Command
2
+
3
+ include HTTY::CLI::CookieClearingCommand
4
+
5
+ # Returns the name of a category under which help for the _config_ command
6
+ # should appear.
7
+ def self.category
8
+ 'Rack'
9
+ end
10
+
11
+ # Returns the arguments for the command-line usage of the _config_ command.
12
+ def self.command_line_arguments
13
+ 'config'
14
+ end
15
+
16
+ # Returns the help text for the _config_ command.
17
+ def self.help
18
+ 'Loads a new config'
19
+ end
20
+
21
+ # Returns the extended help text for the _config_ command.
22
+ def self.help_extended
23
+ 'Loads a config (.ru-File) and sets the built class as the' +
24
+ 'active application. This operation clears cookies.'
25
+ end
26
+
27
+ # Performs the _config_ command.
28
+ def perform
29
+ unless arguments.length == 1
30
+ raise ArgumentError,
31
+ "wrong number of arguments (#{arguments.length} for 1)"
32
+ end
33
+
34
+ add_request_if_has_response do |request|
35
+ request.app_file, request.app = HTTY::Rack::build_app arguments.first
36
+ request
37
+ end
38
+ end
39
+
40
+ end
@@ -0,0 +1,36 @@
1
+ class HTTY::CLI::Commands::Irb < HTTY::CLI::Command
2
+
3
+ # Returns the name of a category under which help for the _irb_ command
4
+ # should appear.
5
+ def self.category
6
+ 'Debug'
7
+ end
8
+
9
+ # Returns the arguments for the command-line usage of the _irb_ command.
10
+ def self.command_line_arguments
11
+ ''
12
+ end
13
+
14
+ # Returns the help text for the _irb_ command.
15
+ def self.help
16
+ 'Starts irb'
17
+ end
18
+
19
+ # Returns the extended help text for the _irb_ command.
20
+ def self.help_extended
21
+ 'Starts irb to let you modify the environment. Use it like IRB, using' +
22
+ '#exit brings you right back.'
23
+ end
24
+
25
+ # Performs the _irb_ command.
26
+ def perform
27
+ unless arguments.length == 0
28
+ raise ArgumentError,
29
+ "wrong number of arguments (#{arguments.length} for 0)"
30
+ end
31
+ require 'irb'
32
+
33
+ IRB::start(__FILE__)
34
+ end
35
+
36
+ end
@@ -0,0 +1,35 @@
1
+ class HTTY::CLI::Commands::Require < HTTY::CLI::Command
2
+
3
+ # Returns the name of a category under which help for the _require_ command
4
+ # should appear.
5
+ def self.category
6
+ 'Rack'
7
+ end
8
+
9
+ # Returns the arguments for the command-line usage of the _require_ command.
10
+ def self.command_line_arguments
11
+ 'file'
12
+ end
13
+
14
+ # Returns the help text for the _require_ command.
15
+ def self.help
16
+ 'requires a file'
17
+ end
18
+
19
+ # Returns the extended help text for the _require_ command.
20
+ def self.help_extended
21
+ 'allows you to require a file. Works like rubys require and allows you' +
22
+ 'to load apps.'
23
+ end
24
+
25
+ # Performs the _require_ command.
26
+ def perform
27
+ unless arguments.length == 1
28
+ raise ArgumentError,
29
+ "wrong number of arguments (#{arguments.length} for 1)"
30
+ end
31
+
32
+ require arguments.first
33
+ end
34
+
35
+ end
@@ -0,0 +1,462 @@
1
+
2
+ # Defines HTTY::Request.
3
+
4
+ require 'pathname'
5
+ require 'uri'
6
+
7
+ module HTTY; end
8
+
9
+ # Encapsulates an HTTP(S) request.
10
+ class HTTY::Rack::Request < HTTY::Payload
11
+ attr_accessor :app, :app_file
12
+
13
+ COOKIES_HEADER_NAME = 'Cookie'
14
+
15
+ METHODS_SENDING_BODY = [:post, :put]
16
+
17
+ # Returns a URI authority (a combination of userinfo, host, and port)
18
+ # corresponding to the specified _components_ hash. Valid _components_ keys
19
+ # include:
20
+ #
21
+ # * <tt>:userinfo</tt>
22
+ # * <tt>:host</tt>
23
+ # * <tt>:port</tt>
24
+ def self.build_authority(components)
25
+ userinfo_and_host = [components[:userinfo],
26
+ components[:host]].compact.join('@')
27
+ all = [userinfo_and_host, components[:port]].compact.join(':')
28
+ return nil if (all == '')
29
+ all
30
+ end
31
+
32
+ # Returns a combination of a URI path, query, and fragment, corresponding to
33
+ # the specified _components_ hash. Valid _components_ keys include:
34
+ #
35
+ # * <tt>:path</tt>
36
+ # * <tt>:query</tt>
37
+ # * <tt>:fragment</tt>
38
+ def self.build_path_query_and_fragment(components)
39
+ path = components[:path]
40
+ query = components[:query] ? "?#{components[:query]}" : nil
41
+ fragment = components[:fragment] ? "##{components[:fragment]}" : nil
42
+ all = [path, query, fragment].compact.join
43
+ return nil if (all == '')
44
+ all
45
+ end
46
+
47
+ # Returns a URI corresponding to the specified _components_ hash, or raises
48
+ # URI::InvalidURIError. Valid _components_ keys include:
49
+ #
50
+ # * <tt>:scheme</tt>
51
+ # * <tt>:userinfo</tt>
52
+ # * <tt>:host</tt>
53
+ # * <tt>:port</tt>
54
+ # * <tt>:path</tt>
55
+ # * <tt>:query</tt>
56
+ # * <tt>:fragment</tt>
57
+ def self.build_uri(components)
58
+ scheme = (components[:scheme] || 'http') + '://'
59
+ authority = build_authority(components)
60
+ path_query_and_fragment = build_path_query_and_fragment(components)
61
+ path_query_and_fragment ||= '/' if authority
62
+ URI.parse([path_query_and_fragment].join)
63
+ end
64
+
65
+ # Returns a URI corresponding to the specified _address_, or raises
66
+ # URI::InvalidURIError.
67
+ def self.parse_uri(address)
68
+ address = '0.0.0.0' if address.nil? || (address == '')
69
+
70
+ scheme_missing = false
71
+ if (address !~ /^[a-z]+:\/\//) && (address !~ /^mailto:/)
72
+ scheme_missing = true
73
+ address = 'http://' + address
74
+ end
75
+
76
+ scheme,
77
+ userinfo,
78
+ host,
79
+ port,
80
+ registry, # Not used by HTTP
81
+ path,
82
+ opaque, # Not used by HTTP
83
+ query,
84
+ fragment = URI.split(address)
85
+
86
+ scheme = nil if scheme_missing
87
+ path = nil if (path == '')
88
+
89
+ unless scheme
90
+ scheme = (port.to_i == URI::HTTPS::DEFAULT_PORT) ? 'https' : 'http'
91
+ end
92
+
93
+ build_uri :scheme => scheme,
94
+ :userinfo => userinfo,
95
+ :host => host,
96
+ :port => port,
97
+ :path => path,
98
+ :query => query,
99
+ :fragment => fragment
100
+ end
101
+
102
+ protected
103
+
104
+ def self.clear_cookies_if_host_changes(request)
105
+ previous_host = request.uri.host
106
+ yield
107
+ request.cookies_remove_all unless request.uri.host == previous_host
108
+ request
109
+ end
110
+
111
+ public
112
+
113
+ # Returns the HTTP method of the request, if any.
114
+ attr_reader :request_method
115
+
116
+ # Returns the response received for the request, if any.
117
+ attr_reader :response
118
+
119
+ # Returns the URI of the request.
120
+ attr_reader :uri
121
+
122
+ # Initializes a new HTTY::Request with a #uri corresponding to the specified
123
+ # _address_.
124
+ def initialize(address = "/")
125
+ super({:headers => [['User-Agent', "htty/#{HTTY::VERSION}"]]})
126
+ @uri = self.class.parse_uri(address)
127
+ establish_content_length
128
+ end
129
+
130
+ def initialize_copy(source) #:nodoc:
131
+ super
132
+ @response = @response.dup if @response
133
+ @uri = @uri.dup
134
+ end
135
+
136
+ # Returns +true+ if _other_request_ is equivalent to the request.
137
+ def ==(other_request)
138
+ return false unless super(other_request)
139
+ return false unless other_request.kind_of?(self.class)
140
+ (other_request.response == response) && (other_request.uri == uri)
141
+ end
142
+ alias :eql? :==
143
+
144
+ # Establishes a new #uri corresponding to the specified _address_. If the host
145
+ # of the _address_ is different from the host of #uri, then #cookies are
146
+ # cleared.
147
+ def address(address)
148
+ uri = self.class.parse_uri(address)
149
+ if response
150
+ dup = dup_without_response
151
+ return self.class.clear_cookies_if_host_changes(dup) do
152
+ dup.uri = uri
153
+ end
154
+ end
155
+
156
+ self.class.clear_cookies_if_host_changes self do
157
+ @uri = uri
158
+ end
159
+ end
160
+
161
+ # Sets the body of the request.
162
+ def body_set(body)
163
+ return dup_without_response.body_set(body) if response
164
+
165
+ @body = body ? body.to_s : nil
166
+ establish_content_length
167
+ end
168
+
169
+ # Clears the body of the request.
170
+ def body_unset
171
+ body_set nil
172
+ end
173
+
174
+ # Makes an HTTP +CONNECT+ request using the path of #uri.
175
+ def connect!
176
+ request! :connect
177
+ end
178
+
179
+ # Appends to #cookies using the specified _name_ (required) and _value_
180
+ # (optional).
181
+ def cookie_add(name, value=nil)
182
+ return dup_without_response.cookie_add(name, value) if response
183
+
184
+ cookies_string = HTTY::CookiesUtil.cookies_to_string(cookies +
185
+ [[name.to_s, value]])
186
+ if cookies_string
187
+ @headers[COOKIES_HEADER_NAME] = cookies_string
188
+ else
189
+ @headers.delete COOKIES_HEADER_NAME
190
+ end
191
+ self
192
+ end
193
+
194
+ # Removes the last element of #cookies having the specified _name_.
195
+ def cookie_remove(name)
196
+ return dup_without_response.cookie_remove(name) if response
197
+
198
+ # Remove just one matching cookie from the end.
199
+ rejected = false
200
+ new_cookies = cookies.reverse.reject do |cookie_name, cookie_value|
201
+ if !rejected && (cookie_name == name)
202
+ rejected = true
203
+ else
204
+ false
205
+ end
206
+ end.reverse
207
+
208
+ cookies_string = HTTY::CookiesUtil.cookies_to_string(new_cookies)
209
+ if cookies_string
210
+ @headers[COOKIES_HEADER_NAME] = cookies_string
211
+ else
212
+ @headers.delete COOKIES_HEADER_NAME
213
+ end
214
+ self
215
+ end
216
+
217
+ # Returns an array of the cookies belonging to the request.
218
+ def cookies
219
+ HTTY::CookiesUtil.cookies_from_string @headers[COOKIES_HEADER_NAME]
220
+ end
221
+
222
+ # Removes all #cookies.
223
+ def cookies_remove_all
224
+ return dup_without_response.cookies_remove_all if response
225
+
226
+ @headers.delete COOKIES_HEADER_NAME
227
+ self
228
+ end
229
+
230
+ # Sets #cookies according to the _Set-Cookie_ header of the specified
231
+ # _response_, or raises either HTTY::NoResponseError or
232
+ # HTTY::NoSetCookieHeaderError.
233
+ def cookies_use(response)
234
+ raise HTTY::NoResponseError unless response
235
+
236
+ cookies_header = response.headers.detect do |name, value|
237
+ name == HTTY::Response::COOKIES_HEADER_NAME
238
+ end
239
+ unless cookies_header && cookies_header.last
240
+ raise HTTY::NoSetCookieHeaderError
241
+ end
242
+ header_set COOKIES_HEADER_NAME, cookies_header.last
243
+ end
244
+
245
+ # Makes an HTTP +DELETE+ request using the path of #uri.
246
+ def delete!
247
+ request! :delete
248
+ end
249
+
250
+ # Establishes a new #uri according to the _Location_ header of the specified
251
+ # _response_, or raises either HTTY::NoResponseError or
252
+ # HTTY::NoLocationHeaderError.
253
+ def follow(response)
254
+ raise HTTY::NoResponseError unless response
255
+
256
+ location_header = response.headers.detect do |name, value|
257
+ name == 'Location'
258
+ end
259
+ unless location_header && location_header.last
260
+ raise HTTY::NoLocationHeaderError
261
+ end
262
+ address location_header.last
263
+ end
264
+
265
+ # Establishes a new #uri with the specified _fragment_.
266
+ def fragment_set(fragment)
267
+ rebuild_uri :fragment => fragment
268
+ end
269
+
270
+ # Establishes a new #uri without a fragment.
271
+ def fragment_unset
272
+ fragment_set nil
273
+ end
274
+
275
+ # Makes an HTTP +GET+ request using the path of #uri.
276
+ def get!
277
+ request! :get
278
+ end
279
+
280
+ # Makes an HTTP +HEAD+ request using the path of #uri.
281
+ def head!
282
+ request! :head
283
+ end
284
+
285
+ # Appends to #headers or changes the element of #headers using the specified
286
+ # _name_ and _value_.
287
+ def header_set(name, value)
288
+ return dup_without_response.header_set(name, value) if response
289
+
290
+ name = name.to_s
291
+ if value.nil?
292
+ @headers.delete name
293
+ return self
294
+ end
295
+
296
+ @headers[name] = value.to_s
297
+ self
298
+ end
299
+
300
+ # Removes the element of #headers having the specified _name_.
301
+ def header_unset(name)
302
+ header_set name, nil
303
+ end
304
+
305
+ # Returns an array of the headers belonging to the payload. If
306
+ # _include_content_length_ is +false+, then a 'Content Length' header will be
307
+ # omitted. If _include_content_length_ is not specified, then it will be
308
+ # +true+ if #request_method is an HTTP method for which body content is
309
+ # expected.
310
+ def headers(include_content_length=
311
+ METHODS_SENDING_BODY.include?(request_method))
312
+ unless include_content_length
313
+ return super().reject do |name, value|
314
+ name == 'Content-Length'
315
+ end
316
+ end
317
+
318
+ super()
319
+ end
320
+
321
+ # Removes all #headers.
322
+ def headers_unset_all
323
+ return dup_without_response.headers_unset_all if response
324
+
325
+ @headers.clear
326
+ self
327
+ end
328
+
329
+ # Establishes a new #uri with the specified _host_.
330
+ def host_set(host)
331
+ rebuild_uri :host => host
332
+ end
333
+
334
+ # Makes an HTTP +OPTIONS+ request using the path of #uri.
335
+ def options!
336
+ request! :options
337
+ end
338
+
339
+ # Makes an HTTP +PATCH+ request using the path of #uri.
340
+ def patch!
341
+ request! :patch
342
+ end
343
+
344
+ # Establishes a new #uri with the specified _path_ which may be absolute or
345
+ # relative.
346
+ def path_set(path)
347
+ absolute_path = (Pathname.new(uri.path) + path).to_s
348
+ rebuild_uri :path => absolute_path
349
+ end
350
+
351
+ # Establishes a new #uri with the specified _port_.
352
+ def port_set(port)
353
+ rebuild_uri :port => port
354
+ end
355
+
356
+ # Makes an HTTP +POST+ request using the path of #uri.
357
+ def post!
358
+ request! :post
359
+ end
360
+
361
+ # Makes an HTTP +PUT+ request using the path of #uri.
362
+ def put!
363
+ request! :put
364
+ end
365
+
366
+ # Establishes a new #uri, with the specified _value_ for the query-string
367
+ # parameter specified by _name_.
368
+ def query_set(name, value)
369
+ query = uri.query ? "&#{uri.query}&" : ''
370
+ parameter = Regexp.new("&#{Regexp.escape name}=.+?&")
371
+ if query =~ parameter
372
+ new_query = value.nil? ?
373
+ query.gsub(parameter, '&') :
374
+ query.gsub(parameter, "&#{name}=#{value}&")
375
+ else
376
+ new_query = value.nil? ? query : "#{query}#{name}=#{value}"
377
+ end
378
+ new_query = new_query.gsub(/^&/, '').gsub(/&$/, '')
379
+ new_query = nil if (new_query == '')
380
+ rebuild_uri :query => new_query
381
+ end
382
+
383
+ # Establishes a new #uri, without the query-string parameter specified by
384
+ # _name_.
385
+ def query_unset(name)
386
+ query_set name, nil
387
+ end
388
+
389
+ # Establishes a new #uri without a query string.
390
+ def query_unset_all
391
+ rebuild_uri :query => nil
392
+ end
393
+
394
+ # Establishes a new #uri with the specified _scheme_.
395
+ def scheme_set(scheme)
396
+ rebuild_uri :scheme => scheme
397
+ end
398
+
399
+ # Makes an HTTP +TRACE+ request using the path of #uri.
400
+ def trace!
401
+ request! :trace
402
+ end
403
+
404
+ # Establishes a new #uri with the specified _userinfo_.
405
+ def userinfo_set(userinfo)
406
+ rebuild_uri :userinfo => userinfo
407
+ end
408
+
409
+ # Establishes a new #uri without userinfo.
410
+ def userinfo_unset
411
+ userinfo_set nil
412
+ end
413
+
414
+ protected
415
+
416
+ def dup_without_response
417
+ request = self.dup
418
+ request.response = nil
419
+ request.instance_variable_set '@request_method', nil
420
+ request
421
+ end
422
+
423
+ def establish_content_length
424
+ header_set 'Content-Length', body.to_s.length
425
+ end
426
+
427
+ def path_query_and_fragment
428
+ self.class.build_path_query_and_fragment :path => uri.path,
429
+ :query => uri.query,
430
+ :fragment => uri.fragment
431
+ end
432
+
433
+ def rebuild_uri(changed_components)
434
+ return dup_without_response.rebuild_uri(changed_components) if response
435
+
436
+ components = URI::HTTP::COMPONENT.inject({}) do |result, c|
437
+ result.merge c => uri.send(c)
438
+ end
439
+ self.class.clear_cookies_if_host_changes self do
440
+ @uri = self.class.build_uri(components.merge(changed_components))
441
+ end
442
+ end
443
+
444
+ attr_writer :response
445
+
446
+ attr_writer :uri
447
+
448
+ private
449
+
450
+ def authority
451
+ self.class.build_authority :userinfo => uri.userinfo,
452
+ :host => uri.host,
453
+ :port => uri.port
454
+ end
455
+
456
+ def request!(method)
457
+ request = response ? dup_without_response : self
458
+ request.instance_variable_set '@request_method', method
459
+ HTTY::Rack::RequestsUtil.send method, request
460
+ end
461
+
462
+ end
@@ -0,0 +1,53 @@
1
+ require 'rack/test'
2
+
3
+ module HTTY::Rack
4
+ class RequestsUtil
5
+ class RackApp
6
+
7
+ def initialize(app)
8
+ @app = app
9
+ end
10
+
11
+ def app
12
+ @app
13
+ end
14
+
15
+ include Rack::Test::Methods
16
+ end
17
+
18
+ class << self
19
+ %w(get post put delete option trace).each do |v|
20
+ define_method(v) do |request|
21
+ request(request) do |app|
22
+ a = RackApp.new(app)
23
+
24
+ a.send(v,
25
+ request.send(:path_query_and_fragment),
26
+ Hash[*request.headers])
27
+ end
28
+ end
29
+ end
30
+ end
31
+
32
+ protected
33
+ def self.http_response_to_status(http_response)
34
+ [http_response.status,
35
+ Rack::Utils::HTTP_STATUS_CODES[http_response.status]]
36
+ end
37
+
38
+ private
39
+ def self.request(request)
40
+ http_response = yield request.app
41
+ headers = []
42
+ http_response.headers.each do |*h|
43
+ headers << h
44
+ end
45
+ request.send :response=,
46
+ HTTY::Response.new(:status => http_response_to_status(http_response),
47
+ :headers => headers,
48
+ :body => http_response.body)
49
+ request
50
+ end
51
+
52
+ end
53
+ end
@@ -0,0 +1,11 @@
1
+ class HTTY::Rack::Session < HTTY::Session
2
+ attr_accessor :app_file
3
+
4
+ def initialize(app_file_name)
5
+ request = HTTY::Rack::Request.new("/")
6
+ request.app_file, request.app = HTTY::Rack.build_app(app_file_name)
7
+ @requests = [request]
8
+ end
9
+
10
+
11
+ end
@@ -0,0 +1,7 @@
1
+ context "htty-rack" do
2
+ context "tests" do
3
+ asserts("do exist") do
4
+ false
5
+ end
6
+ end
7
+ end
@@ -0,0 +1 @@
1
+ require 'riot'
metadata ADDED
@@ -0,0 +1,97 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: htty-rack
3
+ version: !ruby/object:Gem::Version
4
+ prerelease: false
5
+ segments:
6
+ - 0
7
+ - 0
8
+ - 5
9
+ version: 0.0.5
10
+ platform: ruby
11
+ authors:
12
+ - Florian Gilcher
13
+ autorequire:
14
+ bindir: bin
15
+ cert_chain: []
16
+
17
+ date: 2010-09-24 00:00:00 +02:00
18
+ default_executable:
19
+ dependencies:
20
+ - !ruby/object:Gem::Dependency
21
+ name: htty
22
+ prerelease: false
23
+ requirement: &id001 !ruby/object:Gem::Requirement
24
+ none: false
25
+ requirements:
26
+ - - ">="
27
+ - !ruby/object:Gem::Version
28
+ segments:
29
+ - 1
30
+ - 0
31
+ - 0
32
+ version: 1.0.0
33
+ type: :runtime
34
+ version_requirements: *id001
35
+ description: A CLI for rack applications based on htty.
36
+ email:
37
+ - florian.gilcher@asquera.de
38
+ executables:
39
+ - htty-rack
40
+ extensions: []
41
+
42
+ extra_rdoc_files: []
43
+
44
+ files:
45
+ - .gitignore
46
+ - MIT-LICENSE.rdoc
47
+ - README.rdoc
48
+ - Rakefile
49
+ - VERSION
50
+ - bin/htty-rack
51
+ - config.ru
52
+ - htty-rack.gemspec
53
+ - lib/htty/rack.rb
54
+ - lib/htty/rack/cli.rb
55
+ - lib/htty/rack/commands/app.rb
56
+ - lib/htty/rack/commands/config.rb
57
+ - lib/htty/rack/commands/irb.rb
58
+ - lib/htty/rack/commands/require.rb
59
+ - lib/htty/rack/request.rb
60
+ - lib/htty/rack/requests_util.rb
61
+ - lib/htty/rack/session.rb
62
+ - test/rack-htty_test.rb
63
+ - test/test_helper.rb
64
+ has_rdoc: true
65
+ homepage: http://www.github.com/Asquera/htty-rack
66
+ licenses: []
67
+
68
+ post_install_message:
69
+ rdoc_options: []
70
+
71
+ require_paths:
72
+ - lib
73
+ required_ruby_version: !ruby/object:Gem::Requirement
74
+ none: false
75
+ requirements:
76
+ - - ">="
77
+ - !ruby/object:Gem::Version
78
+ segments:
79
+ - 0
80
+ version: "0"
81
+ required_rubygems_version: !ruby/object:Gem::Requirement
82
+ none: false
83
+ requirements:
84
+ - - ">="
85
+ - !ruby/object:Gem::Version
86
+ segments:
87
+ - 0
88
+ version: "0"
89
+ requirements: []
90
+
91
+ rubyforge_project:
92
+ rubygems_version: 1.3.7
93
+ signing_key:
94
+ specification_version: 3
95
+ summary: htty-rack is htty for rack applications
96
+ test_files: []
97
+