Parent

Mechanize::Form

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.

Examples

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']

Attributes

method[RW]
action[RW]
name[RW]
fields[R]
buttons[R]
file_uploads[R]
radiobuttons[R]
checkboxes[R]
enctype[RW]

Content-Type for form data (i.e. application/x-www-form-urlencoded)

encoding[RW]

Character encoding of form data (i.e. UTF-8)

ignore_encoding_error[RW]

When true, character encoding errors will never be never raised on form submission. Default is false

form_node[R]
page[R]

Public Class Methods

new(node, mech=nil, page=nil) click to toggle source
    # 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

Public Instance Methods

[](field_name) click to toggle source

Fetch the value of the first input field with the name passed in

Example

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
[]=(field_name, value) click to toggle source

Set the value of the first input field with the name passed in

Example

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_button_to_query(button) click to toggle source

This method adds a button to the query. If the form needs to be submitted with multiple buttons, pass each button to this method.

     # File lib/mechanize/form.rb, line 259
259:   def add_button_to_query(button)
260:     unless button.node.document == @form_node.document then
261:       message =
262:         "#{button.inspect} does not belong to the same page as "          "the form #{@name.inspect} in #{@page.uri}"
263: 
264:       raise ArgumentError, message
265:     end
266: 
267:     @clicked_buttons << button
268:   end
add_field!(field_name, value = nil) click to toggle source

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
build_query(buttons = []) click to toggle source

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
button_with(criteria) click to toggle source

Find one button that matches criteria Example:

  form.button_with(:value => /submit/).value = 'hello'
     # File lib/mechanize/form.rb, line 328
328:   
buttons_with(criteria) click to toggle source

Find all buttons that match criteria Example:

  form.buttons_with(:value => /submit/).each do |button|
    button.value = 'hello!'
  end
     # File lib/mechanize/form.rb, line 337
337:   elements_with :button
checkbox_with(criteria) click to toggle source

Find one checkbox that matches criteria Example:

  form.checkbox_with(:name => /woo/).check
     # File lib/mechanize/form.rb, line 382
382:   
checkboxes_with(criteria) click to toggle source

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
click_button(button = buttons.first) click to toggle source

Submit form using button. Defaults to the first button.

     # File lib/mechanize/form.rb, line 183
183:   def click_button(button = buttons.first)
184:     submit(button)
185:   end
delete_field!(field_name) click to toggle source

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
dom_class() click to toggle source

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
dom_id() click to toggle source

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
field_with(criteria) click to toggle source

Find one field that matches criteria Example:

  form.field_with(:id => "exact_field_id").value = 'hello'
     # File lib/mechanize/form.rb, line 310
310:   
fields_with(criteria) click to toggle source

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
file_upload_with(criteria) click to toggle source

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:   
file_uploads_with(criteria) click to toggle source

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
has_field?(field_name) click to toggle source

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
Also aliased as: has_key?
has_key?(field_name) click to toggle source
Alias for: has_field?
has_value?(value) click to toggle source
    # File lib/mechanize/form.rb, line 63
63:   def has_value?(value)
64:     fields.find { |f| f.value == value }
65:   end
hidden_field?(field_name) click to toggle source
    # File lib/mechanize/form.rb, line 81
81:   def hidden_field?(field_name)     hiddens.find{|f| f.name == field_name}; end
hiddens() click to toggle source
    # File lib/mechanize/form.rb, line 74
74:   def hiddens  ; @hiddens   ||=  fields.select { |f| f.class == Hidden   }; end
keygens() click to toggle source
    # File lib/mechanize/form.rb, line 76
76:   def keygens  ; @keygens   ||=  fields.select { |f| f.class == Keygen   }; end
keys() click to toggle source
    # File lib/mechanize/form.rb, line 67
67:   def keys; fields.map { |f| f.name }; end
method_missing(meth, *args) click to toggle source

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
radiobutton_with(criteria) click to toggle source

Find one radio button that matches criteria Example:

  form.radiobutton_with(:name => /woo/).check
     # File lib/mechanize/form.rb, line 364
364:   
radiobuttons_with(criteria) click to toggle source

Find all radio buttons that match criteria Example:

  form.radiobuttons_with(:name => /woo/).each do |field|
    field.check
  end
     # File lib/mechanize/form.rb, line 373
373:   elements_with :radiobutton
request_data() click to toggle source

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
reset_button?(button_name) click to toggle source
    # File lib/mechanize/form.rb, line 79
79:   def reset_button?(button_name)     resets.find{|f| f.name == button_name}; end
resets() click to toggle source
    # File lib/mechanize/form.rb, line 72
72:   def resets   ; @resets    ||= buttons.select { |f| f.class == Reset    }; end
set_fields(fields = {}) click to toggle source

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(button=nil, headers = {}) click to toggle source

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
submit_button?(button_name) click to toggle source
    # File lib/mechanize/form.rb, line 78
78:   def submit_button?(button_name)   submits.find{|f| f.name == button_name}; end
submits() click to toggle source
    # File lib/mechanize/form.rb, line 71
71:   def submits  ; @submits   ||= buttons.select { |f| f.class == Submit   }; end
text_field?(field_name) click to toggle source
    # File lib/mechanize/form.rb, line 80
80:   def text_field?(field_name)         texts.find{|f| f.name == field_name}; end
textarea_field?(field_name) click to toggle source
    # File lib/mechanize/form.rb, line 82
82:   def textarea_field?(field_name) textareas.find{|f| f.name == field_name}; end
textareas() click to toggle source
    # File lib/mechanize/form.rb, line 75
75:   def textareas; @textareas ||=  fields.select { |f| f.class == Textarea }; end
texts() click to toggle source
    # File lib/mechanize/form.rb, line 73
73:   def texts    ; @texts     ||=  fields.select { |f| f.class == Text     }; end
values() click to toggle source
    # File lib/mechanize/form.rb, line 69
69:   def values; fields.map { |f| f.value }; end

Private Instance Methods

file_to_multipart(file) click to toggle source
     # 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
from_native_charset(str) click to toggle source
     # 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
mime_value_quote(str) click to toggle source
     # File lib/mechanize/form.rb, line 498
498:   def mime_value_quote(str)
499:     str.gsub(/(["\r\\])/){|s| '\' + s}
500:   end
param_to_multipart(name, value) click to toggle source
     # 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
parse() click to toggle source
     # 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
proc_query(field) click to toggle source

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
rand_string(len = 10) click to toggle source
     # File lib/mechanize/form.rb, line 491
491:   def rand_string(len = 10)
492:     chars = ("a".."z").to_a + ("A".."Z").to_a
493:     string = ""
494:     1.upto(len) { |i| string << chars[rand(chars.size-1)] }
495:     string
496:   end

Disabled; run with --debug to generate this.

[Validate]

Generated with the Darkfish Rdoc Generator 1.1.6.