tenderlove-mechanize 0.9.3.20090623142847 → 0.9.3.20090911221705

Sign up to get free protection for your applications and to get access to all the features.
Files changed (165) hide show
  1. data/Manifest.txt +55 -48
  2. data/Rakefile +12 -22
  3. data/lib/mechanize.rb +618 -4
  4. data/lib/mechanize/chain.rb +33 -0
  5. data/lib/mechanize/chain/auth_headers.rb +78 -0
  6. data/lib/mechanize/chain/body_decoding_handler.rb +46 -0
  7. data/lib/mechanize/chain/connection_resolver.rb +76 -0
  8. data/lib/mechanize/chain/custom_headers.rb +21 -0
  9. data/lib/{www/mechanize → mechanize}/chain/handler.rb +1 -1
  10. data/lib/mechanize/chain/header_resolver.rb +51 -0
  11. data/lib/mechanize/chain/parameter_resolver.rb +22 -0
  12. data/lib/{www/mechanize → mechanize}/chain/post_connect_hook.rb +0 -0
  13. data/lib/mechanize/chain/pre_connect_hook.rb +20 -0
  14. data/lib/mechanize/chain/request_resolver.rb +30 -0
  15. data/lib/mechanize/chain/response_body_parser.rb +38 -0
  16. data/lib/mechanize/chain/response_header_handler.rb +48 -0
  17. data/lib/mechanize/chain/response_reader.rb +39 -0
  18. data/lib/mechanize/chain/ssl_resolver.rb +40 -0
  19. data/lib/mechanize/chain/uri_resolver.rb +75 -0
  20. data/lib/mechanize/content_type_error.rb +14 -0
  21. data/lib/mechanize/cookie.rb +70 -0
  22. data/lib/mechanize/cookie_jar.rb +188 -0
  23. data/lib/mechanize/file.rb +71 -0
  24. data/lib/mechanize/file_response.rb +60 -0
  25. data/lib/mechanize/file_saver.rb +37 -0
  26. data/lib/mechanize/form.rb +378 -0
  27. data/lib/mechanize/form/button.rb +9 -0
  28. data/lib/mechanize/form/check_box.rb +11 -0
  29. data/lib/mechanize/form/field.rb +30 -0
  30. data/lib/mechanize/form/file_upload.rb +22 -0
  31. data/lib/mechanize/form/image_button.rb +21 -0
  32. data/lib/mechanize/form/multi_select_list.rb +67 -0
  33. data/lib/mechanize/form/option.rb +49 -0
  34. data/lib/mechanize/form/radio_button.rb +49 -0
  35. data/lib/mechanize/form/select_list.rb +43 -0
  36. data/lib/mechanize/headers.rb +11 -0
  37. data/lib/mechanize/history.rb +65 -0
  38. data/lib/mechanize/inspect.rb +88 -0
  39. data/lib/{www/mechanize → mechanize}/monkey_patch.rb +4 -6
  40. data/lib/mechanize/page.rb +206 -0
  41. data/lib/mechanize/page/base.rb +8 -0
  42. data/lib/mechanize/page/frame.rb +20 -0
  43. data/lib/mechanize/page/image.rb +26 -0
  44. data/lib/mechanize/page/label.rb +20 -0
  45. data/lib/mechanize/page/link.rb +48 -0
  46. data/lib/mechanize/page/meta.rb +50 -0
  47. data/lib/mechanize/pluggable_parsers.rb +101 -0
  48. data/lib/mechanize/redirect_limit_reached_error.rb +16 -0
  49. data/lib/mechanize/redirect_not_get_or_head_error.rb +18 -0
  50. data/lib/mechanize/response_code_error.rb +22 -0
  51. data/lib/mechanize/unsupported_scheme_error.rb +8 -0
  52. data/lib/mechanize/util.rb +67 -0
  53. data/mechanize.gemspec +8 -8
  54. data/test/chain/test_argument_validator.rb +2 -2
  55. data/test/chain/test_auth_headers.rb +2 -2
  56. data/test/chain/test_custom_headers.rb +2 -2
  57. data/test/chain/test_header_resolver.rb +3 -3
  58. data/test/chain/test_parameter_resolver.rb +4 -4
  59. data/test/chain/test_request_resolver.rb +4 -4
  60. data/test/chain/test_response_reader.rb +3 -3
  61. data/test/helper.rb +1 -1
  62. data/test/htdocs/tc_bad_charset.html +9 -0
  63. data/test/htdocs/tc_charset.html +6 -0
  64. data/test/htdocs/test_bad_encoding.html +52 -0
  65. data/test/test_authenticate.rb +3 -3
  66. data/test/test_bad_links.rb +1 -1
  67. data/test/test_blank_form.rb +1 -1
  68. data/test/test_checkboxes.rb +1 -1
  69. data/test/test_content_type.rb +2 -2
  70. data/test/test_cookie_class.rb +12 -12
  71. data/test/test_cookie_jar.rb +13 -13
  72. data/test/test_cookies.rb +1 -1
  73. data/test/test_encoded_links.rb +1 -1
  74. data/test/test_errors.rb +2 -2
  75. data/test/test_follow_meta.rb +3 -3
  76. data/test/test_form_action.rb +1 -1
  77. data/test/test_form_as_hash.rb +1 -1
  78. data/test/test_form_button.rb +2 -2
  79. data/test/test_form_no_inputname.rb +1 -1
  80. data/test/test_forms.rb +1 -1
  81. data/test/test_frames.rb +1 -1
  82. data/test/test_get_headers.rb +1 -1
  83. data/test/test_gzipping.rb +2 -2
  84. data/test/test_hash_api.rb +1 -1
  85. data/test/test_history.rb +7 -7
  86. data/test/test_history_added.rb +1 -1
  87. data/test/test_html_unscape_forms.rb +7 -7
  88. data/test/test_if_modified_since.rb +1 -1
  89. data/test/test_keep_alive.rb +1 -1
  90. data/test/test_links.rb +2 -2
  91. data/test/test_mech.rb +2 -2
  92. data/test/test_mechanize_file.rb +7 -7
  93. data/test/test_meta.rb +2 -2
  94. data/test/test_multi_select.rb +1 -1
  95. data/test/test_no_attributes.rb +1 -1
  96. data/test/test_option.rb +1 -1
  97. data/test/test_page.rb +3 -3
  98. data/test/test_pluggable_parser.rb +14 -14
  99. data/test/test_post_form.rb +1 -1
  100. data/test/test_pretty_print.rb +2 -2
  101. data/test/test_radiobutton.rb +1 -1
  102. data/test/test_redirect_limit_reached.rb +1 -3
  103. data/test/test_redirect_verb_handling.rb +1 -3
  104. data/test/test_referer.rb +1 -1
  105. data/test/test_relative_links.rb +1 -1
  106. data/test/test_request.rb +1 -1
  107. data/test/test_response_code.rb +3 -3
  108. data/test/test_save_file.rb +3 -3
  109. data/test/test_scheme.rb +3 -3
  110. data/test/test_select.rb +2 -2
  111. data/test/test_select_all.rb +1 -1
  112. data/test/test_select_none.rb +1 -1
  113. data/test/test_select_noopts.rb +1 -1
  114. data/test/test_set_fields.rb +1 -1
  115. data/test/test_ssl_server.rb +1 -1
  116. data/test/test_subclass.rb +1 -1
  117. data/test/test_textarea.rb +1 -1
  118. data/test/test_upload.rb +1 -1
  119. data/test/test_verbs.rb +1 -1
  120. metadata +61 -56
  121. data/lib/www/mechanize.rb +0 -619
  122. data/lib/www/mechanize/chain.rb +0 -34
  123. data/lib/www/mechanize/chain/auth_headers.rb +0 -80
  124. data/lib/www/mechanize/chain/body_decoding_handler.rb +0 -48
  125. data/lib/www/mechanize/chain/connection_resolver.rb +0 -78
  126. data/lib/www/mechanize/chain/custom_headers.rb +0 -23
  127. data/lib/www/mechanize/chain/header_resolver.rb +0 -53
  128. data/lib/www/mechanize/chain/parameter_resolver.rb +0 -24
  129. data/lib/www/mechanize/chain/pre_connect_hook.rb +0 -22
  130. data/lib/www/mechanize/chain/request_resolver.rb +0 -32
  131. data/lib/www/mechanize/chain/response_body_parser.rb +0 -40
  132. data/lib/www/mechanize/chain/response_header_handler.rb +0 -50
  133. data/lib/www/mechanize/chain/response_reader.rb +0 -41
  134. data/lib/www/mechanize/chain/ssl_resolver.rb +0 -42
  135. data/lib/www/mechanize/chain/uri_resolver.rb +0 -77
  136. data/lib/www/mechanize/content_type_error.rb +0 -16
  137. data/lib/www/mechanize/cookie.rb +0 -72
  138. data/lib/www/mechanize/cookie_jar.rb +0 -191
  139. data/lib/www/mechanize/file.rb +0 -73
  140. data/lib/www/mechanize/file_response.rb +0 -62
  141. data/lib/www/mechanize/file_saver.rb +0 -39
  142. data/lib/www/mechanize/form.rb +0 -360
  143. data/lib/www/mechanize/form/button.rb +0 -8
  144. data/lib/www/mechanize/form/check_box.rb +0 -13
  145. data/lib/www/mechanize/form/field.rb +0 -28
  146. data/lib/www/mechanize/form/file_upload.rb +0 -24
  147. data/lib/www/mechanize/form/image_button.rb +0 -23
  148. data/lib/www/mechanize/form/multi_select_list.rb +0 -69
  149. data/lib/www/mechanize/form/option.rb +0 -51
  150. data/lib/www/mechanize/form/radio_button.rb +0 -38
  151. data/lib/www/mechanize/form/select_list.rb +0 -45
  152. data/lib/www/mechanize/headers.rb +0 -12
  153. data/lib/www/mechanize/history.rb +0 -67
  154. data/lib/www/mechanize/inspect.rb +0 -90
  155. data/lib/www/mechanize/page.rb +0 -181
  156. data/lib/www/mechanize/page/base.rb +0 -10
  157. data/lib/www/mechanize/page/frame.rb +0 -22
  158. data/lib/www/mechanize/page/link.rb +0 -50
  159. data/lib/www/mechanize/page/meta.rb +0 -51
  160. data/lib/www/mechanize/pluggable_parsers.rb +0 -103
  161. data/lib/www/mechanize/redirect_limit_reached_error.rb +0 -18
  162. data/lib/www/mechanize/redirect_not_get_or_head_error.rb +0 -20
  163. data/lib/www/mechanize/response_code_error.rb +0 -25
  164. data/lib/www/mechanize/unsupported_scheme_error.rb +0 -10
  165. data/lib/www/mechanize/util.rb +0 -76
@@ -1,73 +0,0 @@
1
- module WWW
2
- class Mechanize
3
- # = Synopsis
4
- # This is the default (and base) class for the Pluggable Parsers. If
5
- # Mechanize cannot find an appropriate class to use for the content type,
6
- # this class will be used. For example, if you download a JPG, Mechanize
7
- # will not know how to parse it, so this class will be instantiated.
8
- #
9
- # This is a good class to use as the base class for building your own
10
- # pluggable parsers.
11
- #
12
- # == Example
13
- # require 'rubygems'
14
- # require 'mechanize'
15
- #
16
- # agent = WWW::Mechanize.new
17
- # agent.get('http://example.com/foo.jpg').class #=> WWW::Mechanize::File
18
- #
19
- class File
20
- attr_accessor :uri, :response, :body, :code, :filename
21
- alias :header :response
22
-
23
- alias :content :body
24
-
25
- def initialize(uri=nil, response=nil, body=nil, code=nil)
26
- @uri, @body, @code = uri, body, code
27
- @response = Headers.new
28
-
29
- # Copy the headers in to a hash to prevent memory leaks
30
- if response
31
- response.each { |k,v|
32
- @response[k] = v
33
- }
34
- end
35
-
36
- @filename = 'index.html'
37
-
38
- # Set the filename
39
- if disposition = @response['content-disposition']
40
- disposition.split(/;\s*/).each do |pair|
41
- k,v = pair.split(/=/, 2)
42
- @filename = v if k && k.downcase == 'filename'
43
- end
44
- else
45
- if @uri
46
- @filename = @uri.path.split(/\//).last || 'index.html'
47
- @filename << ".html" unless @filename =~ /\./
48
- end
49
- end
50
-
51
- yield self if block_given?
52
- end
53
-
54
- # Use this method to save the content of this object to filename
55
- def save_as(filename = nil)
56
- if filename.nil?
57
- filename = @filename
58
- number = 1
59
- while(::File.exists?(filename))
60
- filename = "#{@filename}.#{number}"
61
- number += 1
62
- end
63
- end
64
-
65
- ::File::open(filename, "wb") { |f|
66
- f.write body
67
- }
68
- end
69
-
70
- alias :save :save_as
71
- end
72
- end
73
- end
@@ -1,62 +0,0 @@
1
- module WWW
2
- class Mechanize
3
- ###
4
- # Fake response for dealing with file:/// requests
5
- class FileResponse
6
- def initialize(file_path)
7
- @file_path = file_path
8
- end
9
-
10
- def read_body
11
- if ::File.exists?(@file_path)
12
- if directory?
13
- yield dir_body
14
- else
15
- yield ::File.read(@file_path)
16
- end
17
- else
18
- yield ''
19
- end
20
- end
21
-
22
- def code
23
- ::File.exists?(@file_path) ? 200 : 400
24
- end
25
-
26
- def content_length
27
- return dir_body.length if directory?
28
- ::File.exists?(@file_path) ? ::File.stat(@file_path).size : 0
29
- end
30
-
31
- def each_header; end
32
-
33
- def [](key)
34
- return nil unless key.downcase == 'content-type'
35
- return 'text/html' if directory?
36
- return 'text/html' if ['.html', '.xhtml'].any? { |extn|
37
- @file_path =~ /#{extn}$/
38
- }
39
- nil
40
- end
41
-
42
- def each
43
- end
44
-
45
- def get_fields(key)
46
- []
47
- end
48
-
49
- private
50
- def dir_body
51
- '<html><body>' +
52
- Dir[::File.join(@file_path, '*')].map { |f|
53
- "<a href=\"file://#{f}\">#{::File.basename(f)}</a>"
54
- }.join("\n") + '</body></html>'
55
- end
56
-
57
- def directory?
58
- ::File.directory?(@file_path)
59
- end
60
- end
61
- end
62
- end
@@ -1,39 +0,0 @@
1
- module WWW
2
- class Mechanize
3
- # = Synopsis
4
- # This is a pluggable parser that automatically saves every file
5
- # it encounters. It saves the files as a tree, reflecting the
6
- # host and file path.
7
- #
8
- # == Example to save all PDF's
9
- # require 'rubygems'
10
- # require 'mechanize'
11
- #
12
- # agent = WWW::Mechanize.new
13
- # agent.pluggable_parser.pdf = WWW::Mechanize::FileSaver
14
- # agent.get('http://example.com/foo.pdf')
15
- #
16
- class FileSaver < File
17
- attr_reader :filename
18
-
19
- def initialize(uri=nil, response=nil, body=nil, code=nil)
20
- super(uri, response, body, code)
21
- path = uri.path.empty? ? 'index.html' : uri.path.gsub(/^[\/]*/, '')
22
- path += 'index.html' if path =~ /\/$/
23
-
24
- split_path = path.split(/\//)
25
- filename = split_path.length > 0 ? split_path.pop : 'index.html'
26
- joined_path = split_path.join(::File::SEPARATOR)
27
- path = if joined_path.empty?
28
- uri.host
29
- else
30
- "#{uri.host}#{::File::SEPARATOR}#{joined_path}"
31
- end
32
-
33
- @filename = "#{path}#{::File::SEPARATOR}#{filename}"
34
- FileUtils.mkdir_p(path)
35
- save_as(@filename)
36
- end
37
- end
38
- end
39
- end
@@ -1,360 +0,0 @@
1
- require 'www/mechanize/form/field'
2
- require 'www/mechanize/form/file_upload'
3
- require 'www/mechanize/form/button'
4
- require 'www/mechanize/form/image_button'
5
- require 'www/mechanize/form/radio_button'
6
- require 'www/mechanize/form/check_box'
7
- require 'www/mechanize/form/multi_select_list'
8
- require 'www/mechanize/form/select_list'
9
- require 'www/mechanize/form/option'
10
-
11
- module WWW
12
- class Mechanize
13
- # =Synopsis
14
- # This class encapsulates a form parsed out of an HTML page. Each type
15
- # of input fields available in a form can be accessed through this object.
16
- # See GlobalForm for more methods.
17
- #
18
- # ==Example
19
- # Find a form and print out its fields
20
- # form = page.forms.first # => WWW::Mechanize::Form
21
- # form.fields.each { |f| puts f.name }
22
- # Set the input field 'name' to "Aaron"
23
- # form['name'] = 'Aaron'
24
- # puts form['name']
25
- class Form
26
- attr_accessor :method, :action, :name
27
-
28
- attr_reader :fields, :buttons, :file_uploads, :radiobuttons, :checkboxes
29
- attr_accessor :enctype
30
-
31
- alias :elements :fields
32
-
33
- attr_reader :form_node
34
- attr_reader :page
35
-
36
- def initialize(node, mech=nil, page=nil)
37
- @enctype = node['enctype'] || 'application/x-www-form-urlencoded'
38
- @form_node = node
39
- @action = Util.html_unescape(node['action'])
40
- @method = (node['method'] || 'GET').upcase
41
- @name = node['name']
42
- @clicked_buttons = []
43
- @page = page
44
- @mech = mech
45
-
46
- parse
47
- end
48
-
49
- # Returns whether or not the form contains a field with +field_name+
50
- def has_field?(field_name)
51
- ! fields.find { |f| f.name.eql? field_name }.nil?
52
- end
53
-
54
- alias :has_key? :has_field?
55
-
56
- def has_value?(value)
57
- ! fields.find { |f| f.value.eql? value }.nil?
58
- end
59
-
60
- def keys; fields.map { |f| f.name }; end
61
-
62
- def values; fields.map { |f| f.value }; end
63
-
64
- # Add a field with +field_name+ and +value+
65
- def add_field!(field_name, value = nil)
66
- fields << Field.new(field_name, value)
67
- end
68
-
69
- # This method sets multiple fields on the form. It takes a list of field
70
- # name, value pairs. If there is more than one field found with the
71
- # same name, this method will set the first one found. If you want to
72
- # set the value of a duplicate field, use a value which is a Hash with
73
- # the key as the index in to the form. The index
74
- # is zero based. For example, to set the second field named 'foo', you
75
- # could do the following:
76
- # form.set_fields( :foo => { 1 => 'bar' } )
77
- def set_fields(fields = {})
78
- fields.each do |k,v|
79
- case v
80
- when Hash
81
- v.each do |index, value|
82
- self.fields_with(:name => k.to_s).[](index).value = value
83
- end
84
- else
85
- value = nil
86
- index = 0
87
- [v].flatten.each do |val|
88
- index = val.to_i unless value.nil?
89
- value = val if value.nil?
90
- end
91
- self.fields_with(:name => k.to_s).[](index).value = value
92
- end
93
- end
94
- end
95
-
96
- # Fetch the value of the first input field with the name passed in
97
- # ==Example
98
- # Fetch the value set in the input field 'name'
99
- # puts form['name']
100
- def [](field_name)
101
- f = field(field_name)
102
- f && f.value
103
- end
104
-
105
- # Set the value of the first input field with the name passed in
106
- # ==Example
107
- # Set the value in the input field 'name' to "Aaron"
108
- # form['name'] = 'Aaron'
109
- def []=(field_name, value)
110
- f = field(field_name)
111
- if f.nil?
112
- add_field!(field_name, value)
113
- else
114
- f.value = value
115
- end
116
- end
117
-
118
- # Treat form fields like accessors.
119
- def method_missing(id,*args)
120
- method = id.to_s.gsub(/=$/, '')
121
- if field(method)
122
- return field(method).value if args.empty?
123
- return field(method).value = args[0]
124
- end
125
- super
126
- end
127
-
128
- # Submit this form with the button passed in
129
- def submit button=nil, headers = {}
130
- @mech.submit(self, button, headers)
131
- end
132
-
133
- # Submit form using +button+. Defaults
134
- # to the first button.
135
- def click_button(button = buttons.first)
136
- submit(button)
137
- end
138
-
139
- # This method is sub-method of build_query.
140
- # It converts charset of query value of fields into expected one.
141
- def proc_query(field)
142
- return unless field.query_value
143
- field.query_value.map{|(name, val)|
144
- [from_native_charset(name), from_native_charset(val.to_s)]
145
- }
146
- end
147
- private :proc_query
148
-
149
- def from_native_charset(str, enc=nil)
150
- if page
151
- enc ||= page.encoding
152
- Util.from_native_charset(str,enc) rescue str
153
- else
154
- str
155
- end
156
- end
157
- private :from_native_charset
158
-
159
- # This method builds an array of arrays that represent the query
160
- # parameters to be used with this form. The return value can then
161
- # be used to create a query string for this form.
162
- def build_query(buttons = [])
163
- query = []
164
-
165
- fields().each do |f|
166
- qval = proc_query(f)
167
- query.push(*qval)
168
- end
169
-
170
- checkboxes().each do |f|
171
- if f.checked
172
- qval = proc_query(f)
173
- query.push(*qval)
174
- end
175
- end
176
-
177
- radio_groups = {}
178
- radiobuttons().each do |f|
179
- fname = from_native_charset(f.name)
180
- radio_groups[fname] ||= []
181
- radio_groups[fname] << f
182
- end
183
-
184
- # take one radio button from each group
185
- radio_groups.each_value do |g|
186
- checked = g.select {|f| f.checked}
187
-
188
- if checked.size == 1
189
- f = checked.first
190
- qval = proc_query(f)
191
- query.push(*qval)
192
- elsif checked.size > 1
193
- raise "multiple radiobuttons are checked in the same group!"
194
- end
195
- end
196
-
197
- @clicked_buttons.each { |b|
198
- qval = proc_query(b)
199
- query.push(*qval)
200
- }
201
- query
202
- end
203
-
204
- # This method adds a button to the query. If the form needs to be
205
- # submitted with multiple buttons, pass each button to this method.
206
- def add_button_to_query(button)
207
- @clicked_buttons << button
208
- end
209
-
210
- # This method calculates the request data to be sent back to the server
211
- # for this form, depending on if this is a regular post, get, or a
212
- # multi-part post,
213
- def request_data
214
- query_params = build_query()
215
- case @enctype.downcase
216
- when /^multipart\/form-data/
217
- boundary = rand_string(20)
218
- @enctype = "multipart/form-data; boundary=#{boundary}"
219
- params = []
220
- query_params.each { |k,v| params << param_to_multipart(k, v) unless k.nil? }
221
- @file_uploads.each { |f| params << file_to_multipart(f) }
222
- params.collect { |p| "--#{boundary}\r\n#{p}" }.join('') +
223
- "--#{boundary}--\r\n"
224
- else
225
- WWW::Mechanize::Util.build_query_string(query_params)
226
- end
227
- end
228
-
229
- # Removes all fields with name +field_name+.
230
- def delete_field!(field_name)
231
- @fields.delete_if{ |f| f.name == field_name}
232
- end
233
-
234
- { :field => :fields,
235
- :button => :buttons,
236
- :file_upload => :file_uploads,
237
- :radiobutton => :radiobuttons,
238
- :checkbox => :checkboxes,
239
- }.each do |singular,plural|
240
- eval(<<-eomethod)
241
- def #{plural}_with criteria = {}
242
- criteria = {:name => criteria} if String === criteria
243
- f = #{plural}.find_all do |thing|
244
- criteria.all? { |k,v| v === thing.send(k) }
245
- end
246
- yield f if block_given?
247
- f
248
- end
249
-
250
- def #{singular}_with criteria = {}
251
- f = #{plural}_with(criteria).first
252
- yield f if block_given?
253
- f
254
- end
255
- alias :#{singular} :#{singular}_with
256
- eomethod
257
- end
258
-
259
- private
260
- def parse
261
- @fields = []
262
- @buttons = []
263
- @file_uploads = []
264
- @radiobuttons = []
265
- @checkboxes = []
266
-
267
- # Find all input tags
268
- form_node.search('input').each do |node|
269
- type = (node['type'] || 'text').downcase
270
- name = node['name']
271
- next if name.nil? && !(type == 'submit' || type =='button')
272
- case type
273
- when 'radio'
274
- @radiobuttons << RadioButton.new(node['name'], node['value'], !!node['checked'], self)
275
- when 'checkbox'
276
- @checkboxes << CheckBox.new(node['name'], node['value'], !!node['checked'], self)
277
- when 'file'
278
- @file_uploads << FileUpload.new(node['name'], nil)
279
- when 'submit'
280
- @buttons << Button.new(node['name'], node['value'])
281
- when 'button'
282
- @buttons << Button.new(node['name'], node['value'])
283
- when 'image'
284
- @buttons << ImageButton.new(node['name'], node['value'])
285
- else
286
- @fields << Field.new(node['name'], node['value'] || '')
287
- end
288
- end
289
-
290
- # Find all textarea tags
291
- form_node.search('textarea').each do |node|
292
- next if node['name'].nil?
293
- @fields << Field.new(node['name'], node.inner_text)
294
- end
295
-
296
- # Find all select tags
297
- form_node.search('select').each do |node|
298
- next if node['name'].nil?
299
- if node.has_attribute? 'multiple'
300
- @fields << MultiSelectList.new(node['name'], node)
301
- else
302
- @fields << SelectList.new(node['name'], node)
303
- end
304
- end
305
-
306
- # Find all submit button tags
307
- # FIXME: what can I do with the reset buttons?
308
- form_node.search('button').each do |node|
309
- type = (node['type'] || 'submit').downcase
310
- next if type == 'reset'
311
- @buttons << Button.new(node['name'], node['value'])
312
- end
313
- end
314
-
315
- def rand_string(len = 10)
316
- chars = ("a".."z").to_a + ("A".."Z").to_a
317
- string = ""
318
- 1.upto(len) { |i| string << chars[rand(chars.size-1)] }
319
- string
320
- end
321
-
322
- def mime_value_quote(str)
323
- str.gsub(/(["\r\\])/){|s| '\\' + s}
324
- end
325
-
326
- def param_to_multipart(name, value)
327
- return "Content-Disposition: form-data; name=\"" +
328
- "#{mime_value_quote(name)}\"\r\n" +
329
- "\r\n#{value}\r\n"
330
- end
331
-
332
- def file_to_multipart(file)
333
- file_name = file.file_name ? ::File.basename(file.file_name) : ''
334
- body = "Content-Disposition: form-data; name=\"" +
335
- "#{mime_value_quote(file.name)}\"; " +
336
- "filename=\"#{mime_value_quote(file_name)}\"\r\n" +
337
- "Content-Transfer-Encoding: binary\r\n"
338
-
339
- if file.file_data.nil? and ! file.file_name.nil?
340
- file.file_data = ::File.open(file.file_name, "rb") { |f| f.read }
341
- file.mime_type = WEBrick::HTTPUtils.mime_type(file.file_name,
342
- WEBrick::HTTPUtils::DefaultMimeTypes)
343
- end
344
-
345
- if file.mime_type != nil
346
- body << "Content-Type: #{file.mime_type}\r\n"
347
- end
348
-
349
- body <<
350
- if file.file_data.respond_to? :read
351
- "\r\n#{file.file_data.read}\r\n"
352
- else
353
- "\r\n#{file.file_data}\r\n"
354
- end
355
-
356
- body
357
- end
358
- end
359
- end
360
- end