htty 1.4.1 → 1.5.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.
- checksums.yaml +7 -0
- data/.gitignore +2 -1
- data/.rspec +2 -0
- data/.travis.yml +21 -3
- data/.yardopts +1 -1
- data/Gemfile +2 -2
- data/Guardfile +12 -10
- data/History.markdown +14 -0
- data/{MIT-LICENSE.markdown → License.markdown} +1 -1
- data/README.markdown +50 -65
- data/Rakefile +2 -2
- data/htty.gemspec +2 -2
- data/lib/htty/cli.rb +59 -74
- data/lib/htty/cli/command.rb +21 -20
- data/lib/htty/cli/commands/body_edit.rb +89 -0
- data/lib/htty/cli/commands/query_add.rb +3 -0
- data/lib/htty/cli/commands/query_set.rb +3 -0
- data/lib/htty/cli/commands/userinfo_set.rb +8 -14
- data/lib/htty/cli/display.rb +14 -12
- data/lib/htty/cli/input_device.rb +75 -0
- data/lib/htty/cli/url_escaping.rb +2 -2
- data/lib/htty/headers.rb +81 -0
- data/lib/htty/no_header_error.rb +10 -0
- data/lib/htty/payload.rb +22 -9
- data/lib/htty/request.rb +67 -43
- data/lib/htty/requests_util.rb +22 -8
- data/lib/htty/response.rb +20 -1
- data/lib/htty/uri.rb +16 -0
- data/lib/htty/version.rb +1 -1
- data/spec/integration/htty/cli/commands/query_add_spec.rb +7 -1
- data/spec/integration/htty/cli/commands/query_remove_spec.rb +19 -1
- data/spec/integration/htty/cli/commands/query_set_spec.rb +9 -3
- data/spec/integration/htty/cli/commands/query_unset_spec.rb +8 -2
- data/spec/spec_helper.rb +69 -0
- data/spec/unit/htty/cli/commands/address_spec.rb +1 -1
- data/spec/unit/htty/cli/commands/body_clear_spec.rb +1 -1
- data/spec/unit/htty/cli/commands/body_edit_spec.rb +18 -0
- data/spec/unit/htty/cli/commands/body_request_spec.rb +1 -1
- data/spec/unit/htty/cli/commands/body_response_spec.rb +1 -1
- data/spec/unit/htty/cli/commands/body_set_spec.rb +1 -1
- data/spec/unit/htty/cli/commands/body_unset_spec.rb +1 -1
- data/spec/unit/htty/cli/commands/cd_spec.rb +1 -1
- data/spec/unit/htty/cli/commands/cookie_add_spec.rb +1 -1
- data/spec/unit/htty/cli/commands/cookie_remove_spec.rb +1 -1
- data/spec/unit/htty/cli/commands/cookies_add_spec.rb +1 -1
- data/spec/unit/htty/cli/commands/cookies_clear_spec.rb +1 -1
- data/spec/unit/htty/cli/commands/cookies_remove_all_spec.rb +1 -1
- data/spec/unit/htty/cli/commands/cookies_remove_spec.rb +1 -1
- data/spec/unit/htty/cli/commands/cookies_spec.rb +1 -1
- data/spec/unit/htty/cli/commands/cookies_use_spec.rb +1 -1
- data/spec/unit/htty/cli/commands/delete_spec.rb +1 -1
- data/spec/unit/htty/cli/commands/exit_spec.rb +1 -1
- data/spec/unit/htty/cli/commands/follow_spec.rb +1 -1
- data/spec/unit/htty/cli/commands/form_add_spec.rb +1 -1
- data/spec/unit/htty/cli/commands/form_clear_spec.rb +1 -1
- data/spec/unit/htty/cli/commands/form_remove_all_spec.rb +1 -1
- data/spec/unit/htty/cli/commands/form_remove_spec.rb +1 -1
- data/spec/unit/htty/cli/commands/form_spec.rb +1 -1
- data/spec/unit/htty/cli/commands/fragment_clear_spec.rb +1 -1
- data/spec/unit/htty/cli/commands/fragment_set_spec.rb +1 -1
- data/spec/unit/htty/cli/commands/fragment_unset_spec.rb +1 -1
- data/spec/unit/htty/cli/commands/get_spec.rb +1 -1
- data/spec/unit/htty/cli/commands/header_set_spec.rb +1 -1
- data/spec/unit/htty/cli/commands/header_unset_spec.rb +1 -1
- data/spec/unit/htty/cli/commands/headers_clear_spec.rb +1 -1
- data/spec/unit/htty/cli/commands/headers_request_spec.rb +1 -1
- data/spec/unit/htty/cli/commands/headers_response_spec.rb +1 -1
- data/spec/unit/htty/cli/commands/headers_set_spec.rb +1 -1
- data/spec/unit/htty/cli/commands/headers_unset_all_spec.rb +1 -1
- data/spec/unit/htty/cli/commands/headers_unset_spec.rb +1 -1
- data/spec/unit/htty/cli/commands/help_spec.rb +1 -1
- data/spec/unit/htty/cli/commands/history_spec.rb +1 -1
- data/spec/unit/htty/cli/commands/history_verbose_spec.rb +1 -1
- data/spec/unit/htty/cli/commands/host_set_spec.rb +1 -1
- data/spec/unit/htty/cli/commands/http_delete_spec.rb +1 -1
- data/spec/unit/htty/cli/commands/http_get_spec.rb +1 -1
- data/spec/unit/htty/cli/commands/http_head_spec.rb +1 -1
- data/spec/unit/htty/cli/commands/http_options_spec.rb +1 -1
- data/spec/unit/htty/cli/commands/http_patch_spec.rb +1 -1
- data/spec/unit/htty/cli/commands/http_post_spec.rb +1 -1
- data/spec/unit/htty/cli/commands/http_put_spec.rb +1 -1
- data/spec/unit/htty/cli/commands/http_trace_spec.rb +1 -1
- data/spec/unit/htty/cli/commands/patch_spec.rb +1 -1
- data/spec/unit/htty/cli/commands/path_set_spec.rb +1 -1
- data/spec/unit/htty/cli/commands/port_set_spec.rb +1 -1
- data/spec/unit/htty/cli/commands/post_spec.rb +1 -1
- data/spec/unit/htty/cli/commands/put_spec.rb +1 -1
- data/spec/unit/htty/cli/commands/query_add_spec.rb +1 -1
- data/spec/unit/htty/cli/commands/query_clear_spec.rb +1 -1
- data/spec/unit/htty/cli/commands/query_remove_spec.rb +1 -1
- data/spec/unit/htty/cli/commands/query_set_spec.rb +1 -1
- data/spec/unit/htty/cli/commands/query_unset_all_spec.rb +1 -1
- data/spec/unit/htty/cli/commands/query_unset_spec.rb +1 -1
- data/spec/unit/htty/cli/commands/quit_spec.rb +1 -1
- data/spec/unit/htty/cli/commands/reuse_spec.rb +1 -1
- data/spec/unit/htty/cli/commands/scheme_set_spec.rb +1 -1
- data/spec/unit/htty/cli/commands/shared_examples_for_commands.rb +55 -0
- data/spec/unit/htty/cli/commands/ssl_verification_off_spec.rb +1 -1
- data/spec/unit/htty/cli/commands/ssl_verification_on_spec.rb +1 -1
- data/spec/unit/htty/cli/commands/ssl_verification_spec.rb +1 -1
- data/spec/unit/htty/cli/commands/status_spec.rb +1 -1
- data/spec/unit/htty/cli/commands/undo_spec.rb +1 -1
- data/spec/unit/htty/cli/commands/userinfo_clear_spec.rb +1 -1
- data/spec/unit/htty/cli/commands/userinfo_set_spec.rb +23 -1
- data/spec/unit/htty/cli/commands/userinfo_unset_spec.rb +1 -1
- data/spec/unit/htty/cli/display_spec.rb +84 -0
- data/spec/unit/htty/cli_spec.rb +1 -1
- data/spec/unit/htty/command.rb +47 -0
- data/spec/unit/htty/{ordered_hash_spec.rb → headers_spec.rb} +4 -4
- data/spec/unit/htty/payload_spec.rb +60 -0
- data/spec/unit/htty/preferences_spec.rb +1 -1
- data/spec/unit/htty/request_follow_spec.rb +94 -0
- data/spec/unit/htty/request_spec.rb +5 -187
- data/spec/unit/htty/request_userinfo_spec.rb +208 -0
- data/spec/unit/htty/session_spec.rb +1 -1
- data/spec/unit/htty/shared_examples_for_requests.rb +32 -0
- data/spec/unit/htty/url_escaping.rb +70 -0
- data/spec/unit/htty/version_spec.rb +1 -1
- metadata +43 -30
- data/lib/htty/ordered_hash.rb +0 -68
data/lib/htty/cli/command.rb
CHANGED
|
@@ -27,18 +27,18 @@ class HTTY::CLI::Command
|
|
|
27
27
|
def self.build_for(command_line, attributes={})
|
|
28
28
|
command_line_regexp = make_command_line_regexp
|
|
29
29
|
if (match = (command_line_regexp.match(command_line)))
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
return :unclosed_quote
|
|
30
|
+
begin
|
|
31
|
+
if (arguments = match.captures[0])
|
|
32
|
+
attributes = attributes.merge(
|
|
33
|
+
:arguments => sanitize_arguments(arguments.strip.shellsplit)
|
|
34
|
+
)
|
|
36
35
|
end
|
|
37
|
-
|
|
36
|
+
rescue ArgumentError
|
|
37
|
+
:unclosed_quote
|
|
38
|
+
else
|
|
39
|
+
new(attributes)
|
|
38
40
|
end
|
|
39
|
-
return new(attributes)
|
|
40
41
|
end
|
|
41
|
-
nil
|
|
42
42
|
end
|
|
43
43
|
|
|
44
44
|
# Returns the name of a category under which help for the command should
|
|
@@ -114,14 +114,19 @@ class HTTY::CLI::Command
|
|
|
114
114
|
Array(alias_for)
|
|
115
115
|
end
|
|
116
116
|
|
|
117
|
+
# Escape, split, chop, ... arguments before they are used to build the
|
|
118
|
+
# command
|
|
119
|
+
def self.sanitize_arguments(arguments)
|
|
120
|
+
arguments
|
|
121
|
+
end
|
|
122
|
+
|
|
117
123
|
protected
|
|
118
124
|
|
|
119
125
|
# Displays a notice if cookies are cleared on the specified _request_ in the
|
|
120
126
|
# course of the block.
|
|
121
127
|
def self.notify_if_cookies_cleared(request)
|
|
122
|
-
had_cookies = cookies?(request)
|
|
123
128
|
changed_request = yield
|
|
124
|
-
puts notice('Cookies cleared') if
|
|
129
|
+
puts notice('Cookies cleared') if request.cookies? && !changed_request.cookies?
|
|
125
130
|
changed_request
|
|
126
131
|
end
|
|
127
132
|
|
|
@@ -140,10 +145,6 @@ private
|
|
|
140
145
|
"(?:#{text[0...char_length]}#{rest})?"
|
|
141
146
|
end
|
|
142
147
|
|
|
143
|
-
def self.cookies?(request)
|
|
144
|
-
!request.cookies.empty?
|
|
145
|
-
end
|
|
146
|
-
|
|
147
148
|
def self.make_command_line_regexp
|
|
148
149
|
pattern = Regexp.escape(command_line).gsub(/\\\[(.+)\\\]/) do |optional|
|
|
149
150
|
completion_optional($1)
|
|
@@ -203,11 +204,11 @@ protected
|
|
|
203
204
|
# Yields the last request in #session. If the block returns a different
|
|
204
205
|
# request, it is added to the requests of #session.
|
|
205
206
|
def add_request_if_new
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
207
|
+
last_request = session.requests.last
|
|
208
|
+
maybe_next_request = yield(last_request)
|
|
209
|
+
session.requests << maybe_next_request unless (
|
|
210
|
+
maybe_next_request.nil? or maybe_next_request.equal?(last_request)
|
|
211
|
+
)
|
|
211
212
|
self
|
|
212
213
|
end
|
|
213
214
|
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
require 'tempfile'
|
|
2
|
+
require File.expand_path("#{File.dirname __FILE__}/../command")
|
|
3
|
+
require File.expand_path("#{File.dirname __FILE__}/../display")
|
|
4
|
+
require File.expand_path("#{File.dirname __FILE__}/body_request")
|
|
5
|
+
require File.expand_path("#{File.dirname __FILE__}/body_unset")
|
|
6
|
+
require File.expand_path("#{File.dirname __FILE__}/body_set")
|
|
7
|
+
|
|
8
|
+
module HTTY; end
|
|
9
|
+
|
|
10
|
+
class HTTY::CLI; end
|
|
11
|
+
|
|
12
|
+
module HTTY::CLI::Commands; end
|
|
13
|
+
|
|
14
|
+
# Encapsulates the _body-edit_ command.
|
|
15
|
+
class HTTY::CLI::Commands::BodyEdit < HTTY::CLI::Command
|
|
16
|
+
|
|
17
|
+
include HTTY::CLI::Display
|
|
18
|
+
|
|
19
|
+
# Returns the name of a category under which help for the _body-edit_ command
|
|
20
|
+
# should appear.
|
|
21
|
+
def self.category
|
|
22
|
+
'Building Requests'
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
# Returns the help text for the _body-edit_ command.
|
|
26
|
+
def self.help
|
|
27
|
+
'Sets the body of the request using a text editor'
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
# Returns the extended help text for the _body-edit_ command.
|
|
31
|
+
def self.help_extended
|
|
32
|
+
<<-EOH.gsub(/^(?: |\t)+/, '')
|
|
33
|
+
Sets the body content used for the request. Does not communicate with
|
|
34
|
+
the host.
|
|
35
|
+
|
|
36
|
+
Uses the editor specified in EDITOR environment variable. Your editor will
|
|
37
|
+
open with a temporary file, fill the file with the request body. When you
|
|
38
|
+
are done save the file and quit the editor. The exact content of the
|
|
39
|
+
temporary file will be used as the request body. The temporary file will be
|
|
40
|
+
removed after this command.
|
|
41
|
+
|
|
42
|
+
If you want to choose your editor, start htty with `EDITOR=vim htty`
|
|
43
|
+
replacing 'vim' with your editor of choice.
|
|
44
|
+
EOH
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
# Returns related command classes for the _body-edit_ command.
|
|
48
|
+
def self.see_also_commands
|
|
49
|
+
[ HTTY::CLI::Commands::BodyRequest,
|
|
50
|
+
HTTY::CLI::Commands::BodyUnset,
|
|
51
|
+
HTTY::CLI::Commands::BodySet
|
|
52
|
+
]
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
# Performs the _body-edit_ command.
|
|
56
|
+
def perform
|
|
57
|
+
add_request_if_new do |request|
|
|
58
|
+
request.body_set(with_editor do |editor|
|
|
59
|
+
file = Tempfile.new('htty')
|
|
60
|
+
if last_request_body = session.requests.last.body
|
|
61
|
+
File.open(file.path, 'w+') {|f| f.write(last_request_body)}
|
|
62
|
+
end
|
|
63
|
+
result = system(editor + ' ' + file.path)
|
|
64
|
+
if not result
|
|
65
|
+
return empty_body_because("Unable to use '#{editor}' to edit request's body")
|
|
66
|
+
end
|
|
67
|
+
body = File.read(file.path)
|
|
68
|
+
file.unlink
|
|
69
|
+
body
|
|
70
|
+
end)
|
|
71
|
+
end
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
private
|
|
75
|
+
|
|
76
|
+
def with_editor
|
|
77
|
+
editor = ENV['EDITOR']
|
|
78
|
+
if editor.nil? || editor.empty?
|
|
79
|
+
return empty_body_because('EDITOR environment variable is not set.')
|
|
80
|
+
end
|
|
81
|
+
yield editor
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
def empty_body_because(reason)
|
|
85
|
+
puts notice(reason)
|
|
86
|
+
puts notice("See 'help body-edit' for further informations.")
|
|
87
|
+
empty_body = ''
|
|
88
|
+
end
|
|
89
|
+
end
|
|
@@ -60,6 +60,9 @@ class HTTY::CLI::Commands::QueryAdd < HTTY::CLI::Command
|
|
|
60
60
|
|
|
61
61
|
# Performs the _query-add_ command.
|
|
62
62
|
def perform
|
|
63
|
+
if arguments.empty?
|
|
64
|
+
raise ArgumentError, 'wrong number of arguments (0 for N)'
|
|
65
|
+
end
|
|
63
66
|
add_request_if_new do |request|
|
|
64
67
|
self.class.notify_if_cookies_cleared request do
|
|
65
68
|
escaped_arguments = escape_or_warn_of_escape_sequences(arguments)
|
|
@@ -60,6 +60,9 @@ class HTTY::CLI::Commands::QuerySet < HTTY::CLI::Command
|
|
|
60
60
|
|
|
61
61
|
# Performs the _query-set_ command.
|
|
62
62
|
def perform
|
|
63
|
+
if arguments.empty?
|
|
64
|
+
raise ArgumentError, 'wrong number of arguments (0 for N)'
|
|
65
|
+
end
|
|
63
66
|
add_request_if_new do |request|
|
|
64
67
|
self.class.notify_if_cookies_cleared request do
|
|
65
68
|
escaped_arguments = escape_or_warn_of_escape_sequences(arguments)
|
|
@@ -13,7 +13,7 @@ module HTTY::CLI::Commands; end
|
|
|
13
13
|
# Encapsulates the _userinfo-set_ command.
|
|
14
14
|
class HTTY::CLI::Commands::UserinfoSet < HTTY::CLI::Command
|
|
15
15
|
|
|
16
|
-
|
|
16
|
+
extend HTTY::CLI::UrlEscaping
|
|
17
17
|
|
|
18
18
|
# Returns the name of a category under which help for the _userinfo-set_
|
|
19
19
|
# command should appear.
|
|
@@ -53,26 +53,20 @@ class HTTY::CLI::Commands::UserinfoSet < HTTY::CLI::Command
|
|
|
53
53
|
[HTTY::CLI::Commands::UserinfoUnset, HTTY::CLI::Commands::Address]
|
|
54
54
|
end
|
|
55
55
|
|
|
56
|
+
def self.sanitize_arguments(arguments)
|
|
57
|
+
if (arguments.length == 1) && (arguments.first.scan(':').length == 1)
|
|
58
|
+
arguments = arguments.first.split(':')
|
|
59
|
+
end
|
|
60
|
+
escape_or_warn_of_escape_sequences(arguments)
|
|
61
|
+
end
|
|
62
|
+
|
|
56
63
|
# Performs the _userinfo-set_ command.
|
|
57
64
|
def perform
|
|
58
65
|
add_request_if_new do |request|
|
|
59
|
-
arguments = self.arguments
|
|
60
|
-
if (arguments.length == 1) && (arguments.first.scan(':').length == 1)
|
|
61
|
-
arguments = arguments.first.split(':')
|
|
62
|
-
end
|
|
63
|
-
arguments = escape_mercantile(escape_or_warn_of_escape_sequences(arguments))
|
|
64
66
|
self.class.notify_if_cookies_cleared request do
|
|
65
67
|
request.userinfo_set(*arguments)
|
|
66
68
|
end
|
|
67
69
|
end
|
|
68
70
|
end
|
|
69
71
|
|
|
70
|
-
private
|
|
71
|
-
|
|
72
|
-
def escape_mercantile(arguments)
|
|
73
|
-
arguments.collect do |a|
|
|
74
|
-
a.gsub '@', '%40'
|
|
75
|
-
end
|
|
76
|
-
end
|
|
77
|
-
|
|
78
72
|
end
|
data/lib/htty/cli/display.rb
CHANGED
|
@@ -39,10 +39,10 @@ module HTTY::CLI::Display
|
|
|
39
39
|
|
|
40
40
|
def format(string, *attributes)
|
|
41
41
|
segments = attributes.collect do |a|
|
|
42
|
-
"\
|
|
42
|
+
"\e[#{FORMATS[a]}m"
|
|
43
43
|
end
|
|
44
44
|
segments << string
|
|
45
|
-
segments << "\
|
|
45
|
+
segments << "\e[0m"
|
|
46
46
|
segments.join ''
|
|
47
47
|
end
|
|
48
48
|
|
|
@@ -69,7 +69,6 @@ module HTTY::CLI::Display
|
|
|
69
69
|
|
|
70
70
|
def normal(string)
|
|
71
71
|
return string
|
|
72
|
-
# format string, :foreground_dark_default
|
|
73
72
|
end
|
|
74
73
|
|
|
75
74
|
def pluralize(word, number)
|
|
@@ -83,7 +82,7 @@ module HTTY::CLI::Display
|
|
|
83
82
|
end
|
|
84
83
|
end
|
|
85
84
|
|
|
86
|
-
def
|
|
85
|
+
def formatted_prompt_for(request)
|
|
87
86
|
format_request_uri(request.uri) + normal('> ')
|
|
88
87
|
end
|
|
89
88
|
|
|
@@ -96,7 +95,7 @@ module HTTY::CLI::Display
|
|
|
96
95
|
end
|
|
97
96
|
|
|
98
97
|
def say_header(message, style=:normal)
|
|
99
|
-
puts send(style, notice('')) + highlight(
|
|
98
|
+
puts send(style, notice('')) + highlight(message)
|
|
100
99
|
end
|
|
101
100
|
|
|
102
101
|
def say_hello
|
|
@@ -104,13 +103,17 @@ module HTTY::CLI::Display
|
|
|
104
103
|
strong('HTTP TTY') + normal('. Heck To The Yeah!')
|
|
105
104
|
end
|
|
106
105
|
|
|
106
|
+
def break
|
|
107
|
+
puts ''
|
|
108
|
+
end
|
|
109
|
+
|
|
107
110
|
def show_headers(headers, options={})
|
|
108
|
-
show_asterisk_next_to = options[:show_asterisk_next_to]
|
|
109
|
-
show_mercantile_next_to = options[:show_mercantile_next_to]
|
|
111
|
+
show_asterisk_next_to = (options[:show_asterisk_next_to] || '').downcase
|
|
112
|
+
show_mercantile_next_to = (options[:show_mercantile_next_to] || '').downcase
|
|
110
113
|
|
|
111
114
|
asterisk_symbol, mercantile_symbol = nil, nil
|
|
112
115
|
margin = headers.inject 0 do |result, header|
|
|
113
|
-
header_name = header.first
|
|
116
|
+
header_name = header.first.downcase
|
|
114
117
|
asterisk_symbol ||= (header_name == show_asterisk_next_to) ? '*' : nil
|
|
115
118
|
mercantile_symbol ||= (header_name == show_mercantile_next_to) ? '@' : nil
|
|
116
119
|
asterisk = (header_name == show_asterisk_next_to) ? asterisk_symbol : ''
|
|
@@ -119,10 +122,9 @@ module HTTY::CLI::Display
|
|
|
119
122
|
result].max
|
|
120
123
|
end
|
|
121
124
|
headers.each do |name, value|
|
|
122
|
-
asterisk = (name == show_asterisk_next_to) ? asterisk_symbol : nil
|
|
123
|
-
mercantile = (name == show_mercantile_next_to) ? mercantile_symbol : nil
|
|
124
|
-
justified_name = name.rjust margin -
|
|
125
|
-
[asterisk.to_s.length, mercantile.to_s.length].max
|
|
125
|
+
asterisk = (name.downcase == show_asterisk_next_to) ? asterisk_symbol : nil
|
|
126
|
+
mercantile = (name.downcase == show_mercantile_next_to) ? mercantile_symbol : nil
|
|
127
|
+
justified_name = name.rjust margin - [asterisk.to_s.length, mercantile.to_s.length].max
|
|
126
128
|
puts "#{justified_name}:#{strong(asterisk || mercantile)} " + value
|
|
127
129
|
end
|
|
128
130
|
end
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
require 'readline'
|
|
2
|
+
|
|
3
|
+
module HTTY::CLI::InputDevice
|
|
4
|
+
def self.new(display)
|
|
5
|
+
if STDIN.tty?
|
|
6
|
+
TTY.new(display)
|
|
7
|
+
else
|
|
8
|
+
Pipe.new(display)
|
|
9
|
+
end
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
class Pipe
|
|
13
|
+
def initialize(display)
|
|
14
|
+
@display = display
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def commands
|
|
18
|
+
STDIN.each_line do |command_line|
|
|
19
|
+
command_line.chomp!
|
|
20
|
+
command_line.strip!
|
|
21
|
+
next if command_line.empty?
|
|
22
|
+
@display.line(command_line)
|
|
23
|
+
yield command_line
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
class TTY
|
|
29
|
+
def initialize(display)
|
|
30
|
+
enable_completion
|
|
31
|
+
@display = display
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def commands
|
|
35
|
+
loop do
|
|
36
|
+
begin
|
|
37
|
+
command_line = ''
|
|
38
|
+
while command_line.empty? do
|
|
39
|
+
if (command_line = Readline.readline(@display.formatted_prompt, true)).nil?
|
|
40
|
+
raise Interrupt
|
|
41
|
+
end
|
|
42
|
+
if whitespace?(command_line) || repeat?(command_line)
|
|
43
|
+
Readline::HISTORY.pop
|
|
44
|
+
end
|
|
45
|
+
command_line.chomp!
|
|
46
|
+
command_line.strip!
|
|
47
|
+
end
|
|
48
|
+
yield command_line
|
|
49
|
+
rescue Interrupt
|
|
50
|
+
@display.break
|
|
51
|
+
yield 'quit'
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
private
|
|
57
|
+
|
|
58
|
+
def enable_completion
|
|
59
|
+
Readline.completion_proc = proc do |input|
|
|
60
|
+
autocomplete_list = HTTY::CLI::Commands.select do |c|
|
|
61
|
+
c.complete_for? input
|
|
62
|
+
end
|
|
63
|
+
autocomplete_list.collect(&:raw_name)
|
|
64
|
+
end
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
def repeat?(command_line)
|
|
68
|
+
command_line == Readline::HISTORY.to_a[-2]
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
def whitespace?(command_line)
|
|
72
|
+
command_line.strip.empty?
|
|
73
|
+
end
|
|
74
|
+
end
|
|
75
|
+
end
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
require 'uri'
|
|
2
1
|
require File.expand_path("#{File.dirname __FILE__}/display")
|
|
2
|
+
require File.expand_path("#{File.dirname __FILE__}/../uri")
|
|
3
3
|
|
|
4
4
|
module HTTY; end
|
|
5
5
|
|
|
@@ -17,7 +17,7 @@ module HTTY::CLI::UrlEscaping
|
|
|
17
17
|
'sequences'
|
|
18
18
|
a
|
|
19
19
|
else
|
|
20
|
-
URI.
|
|
20
|
+
HTTY::URI.escape_component(a)
|
|
21
21
|
end
|
|
22
22
|
end
|
|
23
23
|
end
|
data/lib/htty/headers.rb
ADDED
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
require 'uri'
|
|
2
|
+
require 'base64'
|
|
3
|
+
|
|
4
|
+
module HTTY; end
|
|
5
|
+
|
|
6
|
+
# Represents the Headers of a Request or a Response. Headers preserve the
|
|
7
|
+
# insertion order and are case insensitive. A custom Hash is used because Hash
|
|
8
|
+
# did not have this behavior in Ruby v1.8.7 and earlier.
|
|
9
|
+
class HTTY::Headers
|
|
10
|
+
|
|
11
|
+
def initialize(hash={})
|
|
12
|
+
@inner_hash = {}
|
|
13
|
+
@inner_keys = {}
|
|
14
|
+
@ordered_keys = []
|
|
15
|
+
hash.each_pair do |key, value|
|
|
16
|
+
self[key] = value
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def [](key)
|
|
21
|
+
@inner_hash[key.downcase]
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def []=(key, value)
|
|
25
|
+
@ordered_keys << key.downcase unless @inner_hash.key?(key.downcase)
|
|
26
|
+
@inner_keys[key.downcase] = key
|
|
27
|
+
@inner_hash[key.downcase] = value
|
|
28
|
+
self
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def ==(other_hash)
|
|
32
|
+
if other_hash.kind_of?(self.class)
|
|
33
|
+
return (other_hash.instance_variable_get('@inner_hash') == @inner_hash) &&
|
|
34
|
+
(other_hash.instance_variable_get('@inner_keys') == @inner_keys)
|
|
35
|
+
end
|
|
36
|
+
if other_hash.kind_of?(@inner_hash.class)
|
|
37
|
+
return other_hash.keys.all? do |k|
|
|
38
|
+
other_hash[k] == @inner_hash[k]
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
false
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def clear
|
|
45
|
+
@inner_hash.clear
|
|
46
|
+
@inner_keys.clear
|
|
47
|
+
@ordered_keys.clear
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def delete(key)
|
|
51
|
+
@ordered_keys.delete(key.downcase) if @inner_hash.key?(key.downcase)
|
|
52
|
+
@inner_keys.delete(key.downcase)
|
|
53
|
+
@inner_hash.delete(key.downcase)
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
def empty?
|
|
57
|
+
@inner_hash.empty?
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
def to_a
|
|
61
|
+
@ordered_keys.inject([]) do |result, normalized_key|
|
|
62
|
+
result + [[@inner_keys[normalized_key], @inner_hash[normalized_key]]]
|
|
63
|
+
end
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
def self.basic_authentication_for(username, password = nil)
|
|
67
|
+
['Authorization',
|
|
68
|
+
'Basic ' + Base64.encode64(
|
|
69
|
+
URI.unescape([username, password].compact.join(':'))
|
|
70
|
+
).chomp
|
|
71
|
+
]
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
def self.credentials_from(basic_authentication)
|
|
75
|
+
if match = /^Basic (.+)$/.match(basic_authentication)
|
|
76
|
+
credentials = Base64.decode64(match[1]).split(':')
|
|
77
|
+
return yield *credentials if block_given?
|
|
78
|
+
return credentials
|
|
79
|
+
end
|
|
80
|
+
end
|
|
81
|
+
end
|