This class encapsulates a form parsed out of an HTML page. Each type of input fields available in a form can be accessed through this object.
Find a form and print out its fields
form = page.forms.first # => Mechanize::Form form.fields.each { |f| puts f.name }
Set the input field ‘name’ to “Aaron“
form['name'] = 'Aaron' puts form['name']
# File lib/mechanize/form.rb, line 41 41: def initialize(node, mech=nil, page=nil) 42: @enctype = node['enctype'] || 'application/x-www-form-urlencoded' 43: @form_node = node 44: @action = Mechanize::Util.html_unescape(node['action']) 45: @method = (node['method'] || 'GET').upcase 46: @name = node['name'] 47: @clicked_buttons = [] 48: @page = page 49: @mech = mech 50: 51: @encoding = node['accept-charset'] || (page && page.encoding) || nil 52: @ignore_encoding_error = false 53: parse 54: end
Fetch the value of the first input field with the name passed in
Fetch the value set in the input field ‘name’
puts form['name']
# File lib/mechanize/form.rb, line 146 146: def [](field_name) 147: f = field(field_name) 148: f && f.value 149: end
Set the value of the first input field with the name passed in
Set the value in the input field ‘name’ to “Aaron“
form['name'] = 'Aaron'
# File lib/mechanize/form.rb, line 155 155: def []=(field_name, value) 156: f = field(field_name) 157: if f 158: f.value = value 159: else 160: add_field!(field_name, value) 161: end 162: end
Add a field with field_name and value
# File lib/mechanize/form.rb, line 103 103: def add_field!(field_name, value = nil) 104: fields << Field.new({'name' => field_name}, value) 105: end
This method builds an array of arrays that represent the query parameters to be used with this form. The return value can then be used to create a query string for this form.
# File lib/mechanize/form.rb, line 206 206: def build_query(buttons = []) 207: query = [] 208: @mech.log.info("form encoding: #{encoding}") if @mech && @mech.log 209: 210: successful_controls = [] 211: 212: (fields + checkboxes).sort.each do |f| 213: case f 214: when Mechanize::Form::CheckBox 215: if f.checked 216: successful_controls << f 217: end 218: when Mechanize::Form::Field 219: successful_controls << f 220: end 221: end 222: 223: radio_groups = {} 224: radiobuttons.each do |f| 225: fname = from_native_charset(f.name) 226: radio_groups[fname] ||= [] 227: radio_groups[fname] << f 228: end 229: 230: # take one radio button from each group 231: radio_groups.each_value do |g| 232: checked = g.select {|f| f.checked} 233: 234: if checked.uniq.size > 1 then 235: values = checked.map { |button| button.value }.join(', ').inspect 236: name = checked.first.name.inspect 237: raise Mechanize::Error, 238: "radiobuttons #{values} are checked in the #{name} group, " "only one is allowed" 239: else 240: successful_controls << checked.first unless checked.empty? 241: end 242: end 243: 244: @clicked_buttons.each { |b| 245: successful_controls << b 246: } 247: 248: successful_controls.sort.each do |ctrl| # DOM order 249: qval = proc_query(ctrl) 250: query.push(*qval) 251: end 252: 253: query 254: end
Find one checkbox that matches criteria Example:
form.checkbox_with(:name => /woo/).check
# File lib/mechanize/form.rb, line 382
382:
Find all checkboxes that match criteria Example:
form.checkboxes_with(:name => /woo/).each do |field| field.check end
# File lib/mechanize/form.rb, line 391 391: elements_with :checkbox, :checkboxes
Removes all fields with name field_name.
# File lib/mechanize/form.rb, line 299 299: def delete_field!(field_name) 300: @fields.delete_if{ |f| f.name == field_name} 301: end
This method is a shortcut to get form’s DOM class. Common usage:
page.form_with(:dom_class => "foorm")
Note that you can also use :class to get to this method:
page.form_with(:class => "foorm")
# File lib/mechanize/form.rb, line 98 98: def dom_class 99: form_node['class'] 100: end
This method is a shortcut to get form’s DOM id. Common usage:
page.form_with(:dom_id => "foorm")
Note that you can also use :id to get to this method:
page.form_with(:id => "foorm")
# File lib/mechanize/form.rb, line 89 89: def dom_id 90: form_node['id'] 91: end
Find one field that matches criteria Example:
form.field_with(:id => "exact_field_id").value = 'hello'
# File lib/mechanize/form.rb, line 310
310:
Find all fields that match criteria Example:
form.fields_with(:value => /foo/).each do |field| field.value = 'hello!' end
# File lib/mechanize/form.rb, line 319 319: elements_with :field
Find one file upload field that matches criteria Example:
form.file_upload_with(:file_name => /picture/).value = 'foo'
# File lib/mechanize/form.rb, line 346
346:
Find all file upload fields that match criteria Example:
form.file_uploads_with(:file_name => /picutre/).each do |field| field.value = 'foo!' end
# File lib/mechanize/form.rb, line 355 355: elements_with :file_upload
Returns whether or not the form contains a field with field_name
# File lib/mechanize/form.rb, line 57 57: def has_field?(field_name) 58: fields.find { |f| f.name == field_name } 59: end
# File lib/mechanize/form.rb, line 63 63: def has_value?(value) 64: fields.find { |f| f.value == value } 65: end
# File lib/mechanize/form.rb, line 76 76: def keygens ; @keygens ||= fields.select { |f| f.class == Keygen }; end
# File lib/mechanize/form.rb, line 67 67: def keys; fields.map { |f| f.name }; end
Treat form fields like accessors.
# File lib/mechanize/form.rb, line 165 165: def method_missing(meth, *args) 166: method = meth.to_s.gsub(/=$/, '') 167: 168: if field(method) 169: return field(method).value if args.empty? 170: return field(method).value = args[0] 171: end 172: 173: super 174: end
This method calculates the request data to be sent back to the server for this form, depending on if this is a regular post, get, or a multi-part post,
# File lib/mechanize/form.rb, line 274 274: def request_data 275: query_params = build_query() 276: 277: case @enctype.downcase 278: when /^multipart\/form-data/ 279: boundary = rand_string(20) 280: @enctype = "multipart/form-data; boundary=#{boundary}" 281: 282: params = query_params.map do |k,v| 283: param_to_multipart(k, v) if k 284: end.compact 285: 286: params.concat @file_uploads.map { |f| file_to_multipart(f) } 287: 288: params.map do |part| 289: part.force_encoding('ASCII-8BIT') if part.respond_to? :force_encoding 290: "--#{boundary}\r\n#{part}" 291: end.join('') + 292: "--#{boundary}--\r\n" 293: else 294: Mechanize::Util.build_query_string(query_params) 295: end 296: end
# File lib/mechanize/form.rb, line 72 72: def resets ; @resets ||= buttons.select { |f| f.class == Reset }; end
This method sets multiple fields on the form. It takes a list of fields which are name, value pairs.
If there is more than one field found with the same name, this method will set the first one found. If you want to set the value of a duplicate field, use a value which is a Hash with the key as the index in to the form. The index is zero based.
For example, to set the second field named ‘foo’, you could do the following:
form.set_fields :foo => { 1 => 'bar' }
# File lib/mechanize/form.rb, line 121 121: def set_fields fields = {} 122: fields.each do |name, v| 123: case v 124: when Hash 125: v.each do |index, value| 126: self.fields_with(:name => name.to_s)[index].value = value 127: end 128: else 129: value = nil 130: index = 0 131: 132: [v].flatten.each do |val| 133: index = val.to_i if value 134: value = val unless value 135: end 136: 137: self.fields_with(:name => name.to_s)[index].value = value 138: end 139: end 140: end
Submit this form with the button passed in
# File lib/mechanize/form.rb, line 177 177: def submit button=nil, headers = {} 178: @mech.submit(self, button, headers) 179: end
# File lib/mechanize/form.rb, line 71 71: def submits ; @submits ||= buttons.select { |f| f.class == Submit }; end
# File lib/mechanize/form.rb, line 80 80: def text_field?(field_name) texts.find{|f| f.name == field_name}; end
# File lib/mechanize/form.rb, line 82 82: def textarea_field?(field_name) textareas.find{|f| f.name == field_name}; end
# File lib/mechanize/form.rb, line 75 75: def textareas; @textareas ||= fields.select { |f| f.class == Textarea }; end
# File lib/mechanize/form.rb, line 508 508: def file_to_multipart(file) 509: file_name = file.file_name ? ::File.basename(file.file_name) : '' 510: body = "Content-Disposition: form-data; name=\"" + 511: "#{mime_value_quote(file.name)}\"; " + 512: "filename=\"#{mime_value_quote(file_name)}\"\r\n" + 513: "Content-Transfer-Encoding: binary\r\n" 514: 515: if file.file_data.nil? and file.file_name 516: file.file_data = open(file.file_name, "rb") { |f| f.read } 517: file.mime_type = 518: WEBrick::HTTPUtils.mime_type(file.file_name, 519: WEBrick::HTTPUtils::DefaultMimeTypes) 520: end 521: 522: if file.mime_type 523: body << "Content-Type: #{file.mime_type}\r\n" 524: end 525: 526: body << 527: if file.file_data.respond_to? :read 528: "\r\n#{file.file_data.read}\r\n" 529: else 530: "\r\n#{file.file_data}\r\n" 531: end 532: 533: body 534: end
# File lib/mechanize/form.rb, line 197 197: def from_native_charset str 198: Mechanize::Util.from_native_charset(str, encoding, @ignore_encoding_error, 199: @mech && @mech.log) 200: end
# File lib/mechanize/form.rb, line 498 498: def mime_value_quote(str) 499: str.gsub(/(["\r\\])/){|s| '\' + s} 500: end
# File lib/mechanize/form.rb, line 502 502: def param_to_multipart(name, value) 503: return "Content-Disposition: form-data; name=\"" + 504: "#{mime_value_quote(name)}\"\r\n" + 505: "\r\n#{value}\r\n" 506: end
# File lib/mechanize/form.rb, line 423 423: def parse 424: @fields = [] 425: @buttons = [] 426: @file_uploads = [] 427: @radiobuttons = [] 428: @checkboxes = [] 429: 430: # Find all input tags 431: form_node.search('input').each do |node| 432: type = (node['type'] || 'text').downcase 433: name = node['name'] 434: next if name.nil? && !]submit button image].include?(type) 435: case type 436: when 'radio' 437: @radiobuttons << RadioButton.new(node, self) 438: when 'checkbox' 439: @checkboxes << CheckBox.new(node, self) 440: when 'file' 441: @file_uploads << FileUpload.new(node, nil) 442: when 'submit' 443: @buttons << Submit.new(node) 444: when 'button' 445: @buttons << Button.new(node) 446: when 'reset' 447: @buttons << Reset.new(node) 448: when 'image' 449: @buttons << ImageButton.new(node) 450: when 'hidden' 451: @fields << Hidden.new(node, node['value'] || '') 452: when 'text' 453: @fields << Text.new(node, node['value'] || '') 454: when 'textarea' 455: @fields << Textarea.new(node, node['value'] || '') 456: else 457: @fields << Field.new(node, node['value'] || '') 458: end 459: end 460: 461: # Find all textarea tags 462: form_node.search('textarea').each do |node| 463: next unless node['name'] 464: @fields << Textarea.new(node, node.inner_text) 465: end 466: 467: # Find all select tags 468: form_node.search('select').each do |node| 469: next unless node['name'] 470: if node.has_attribute? 'multiple' 471: @fields << MultiSelectList.new(node) 472: else 473: @fields << SelectList.new(node) 474: end 475: end 476: 477: # Find all submit button tags 478: # FIXME: what can I do with the reset buttons? 479: form_node.search('button').each do |node| 480: type = (node['type'] || 'submit').downcase 481: next if type == 'reset' 482: @buttons << Button.new(node) 483: end 484: 485: # Find all keygen tags 486: form_node.search('keygen').each do |node| 487: @fields << Keygen.new(node, node['value'] || '') 488: end 489: end
This method is sub-method of build_query. It converts charset of query value of fields into expected one.
# File lib/mechanize/form.rb, line 189 189: def proc_query(field) 190: return unless field.query_value 191: field.query_value.map{|(name, val)| 192: [from_native_charset(name), from_native_charset(val.to_s)] 193: } 194: end
Disabled; run with --debug to generate this.
Generated with the Darkfish Rdoc Generator 1.1.6.