mechanize 2.0.1 → 2.1.pre.1

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of mechanize might be problematic. Click here for more details.

Files changed (148) hide show
  1. data.tar.gz.sig +0 -0
  2. data/CHANGELOG.rdoc +82 -0
  3. data/EXAMPLES.rdoc +1 -1
  4. data/FAQ.rdoc +9 -9
  5. data/Manifest.txt +35 -48
  6. data/README.rdoc +2 -1
  7. data/Rakefile +16 -3
  8. data/lib/mechanize.rb +809 -392
  9. data/lib/mechanize/content_type_error.rb +10 -11
  10. data/lib/mechanize/cookie.rb +193 -60
  11. data/lib/mechanize/cookie_jar.rb +39 -86
  12. data/lib/mechanize/download.rb +59 -0
  13. data/lib/mechanize/element_matcher.rb +1 -0
  14. data/lib/mechanize/file.rb +61 -76
  15. data/lib/mechanize/file_saver.rb +37 -35
  16. data/lib/mechanize/form.rb +475 -410
  17. data/lib/mechanize/form/button.rb +4 -7
  18. data/lib/mechanize/form/check_box.rb +10 -9
  19. data/lib/mechanize/form/field.rb +52 -42
  20. data/lib/mechanize/form/file_upload.rb +17 -19
  21. data/lib/mechanize/form/hidden.rb +3 -0
  22. data/lib/mechanize/form/image_button.rb +15 -16
  23. data/lib/mechanize/form/keygen.rb +34 -0
  24. data/lib/mechanize/form/multi_select_list.rb +20 -9
  25. data/lib/mechanize/form/option.rb +48 -47
  26. data/lib/mechanize/form/radio_button.rb +52 -45
  27. data/lib/mechanize/form/reset.rb +3 -0
  28. data/lib/mechanize/form/select_list.rb +10 -6
  29. data/lib/mechanize/form/submit.rb +3 -0
  30. data/lib/mechanize/form/text.rb +3 -0
  31. data/lib/mechanize/form/textarea.rb +3 -0
  32. data/lib/mechanize/headers.rb +17 -19
  33. data/lib/mechanize/history.rb +60 -61
  34. data/lib/mechanize/http.rb +5 -0
  35. data/lib/mechanize/http/agent.rb +485 -218
  36. data/lib/mechanize/http/auth_challenge.rb +59 -0
  37. data/lib/mechanize/http/auth_realm.rb +31 -0
  38. data/lib/mechanize/http/content_disposition_parser.rb +188 -0
  39. data/lib/mechanize/http/www_authenticate_parser.rb +155 -0
  40. data/lib/mechanize/monkey_patch.rb +14 -35
  41. data/lib/mechanize/page.rb +34 -2
  42. data/lib/mechanize/page/base.rb +6 -7
  43. data/lib/mechanize/page/frame.rb +5 -5
  44. data/lib/mechanize/page/image.rb +23 -23
  45. data/lib/mechanize/page/label.rb +16 -16
  46. data/lib/mechanize/page/link.rb +16 -0
  47. data/lib/mechanize/page/meta_refresh.rb +19 -7
  48. data/lib/mechanize/parser.rb +173 -0
  49. data/lib/mechanize/pluggable_parsers.rb +126 -83
  50. data/lib/mechanize/redirect_limit_reached_error.rb +16 -13
  51. data/lib/mechanize/redirect_not_get_or_head_error.rb +18 -16
  52. data/lib/mechanize/response_code_error.rb +16 -17
  53. data/lib/mechanize/robots_disallowed_error.rb +22 -23
  54. data/lib/mechanize/test_case.rb +659 -0
  55. data/lib/mechanize/unauthorized_error.rb +3 -0
  56. data/lib/mechanize/unsupported_scheme_error.rb +4 -6
  57. data/lib/mechanize/util.rb +0 -12
  58. data/test/htdocs/form_order_test.html +11 -0
  59. data/test/htdocs/form_test.html +2 -2
  60. data/test/htdocs/tc_links.html +1 -0
  61. data/test/test_mechanize.rb +367 -59
  62. data/test/test_mechanize_cookie.rb +69 -4
  63. data/test/test_mechanize_cookie_jar.rb +200 -124
  64. data/test/test_mechanize_download.rb +43 -0
  65. data/test/test_mechanize_file.rb +53 -45
  66. data/test/{test_mechanize_file_response.rb → test_mechanize_file_connection.rb} +2 -2
  67. data/test/test_mechanize_file_request.rb +2 -2
  68. data/test/test_mechanize_file_saver.rb +21 -0
  69. data/test/test_mechanize_form.rb +345 -46
  70. data/test/test_mechanize_form_check_box.rb +5 -4
  71. data/test/test_mechanize_form_encoding.rb +10 -16
  72. data/test/test_mechanize_form_field.rb +45 -3
  73. data/test/test_mechanize_form_file_upload.rb +20 -0
  74. data/test/test_mechanize_form_image_button.rb +2 -2
  75. data/test/test_mechanize_form_keygen.rb +32 -0
  76. data/test/test_mechanize_form_multi_select_list.rb +84 -0
  77. data/test/test_mechanize_form_option.rb +55 -0
  78. data/test/test_mechanize_form_radio_button.rb +78 -0
  79. data/test/test_mechanize_form_select_list.rb +76 -0
  80. data/test/test_mechanize_form_textarea.rb +8 -7
  81. data/test/{test_headers.rb → test_mechanize_headers.rb} +4 -2
  82. data/test/test_mechanize_history.rb +103 -0
  83. data/test/test_mechanize_http_agent.rb +525 -17
  84. data/test/test_mechanize_http_auth_challenge.rb +39 -0
  85. data/test/test_mechanize_http_auth_realm.rb +49 -0
  86. data/test/test_mechanize_http_content_disposition_parser.rb +118 -0
  87. data/test/test_mechanize_http_www_authenticate_parser.rb +146 -0
  88. data/test/test_mechanize_link.rb +10 -14
  89. data/test/test_mechanize_page.rb +118 -0
  90. data/test/test_mechanize_page_encoding.rb +48 -13
  91. data/test/test_mechanize_page_frame.rb +16 -0
  92. data/test/test_mechanize_page_link.rb +27 -19
  93. data/test/test_mechanize_page_meta_refresh.rb +26 -14
  94. data/test/test_mechanize_parser.rb +289 -0
  95. data/test/test_mechanize_pluggable_parser.rb +52 -0
  96. data/test/test_mechanize_redirect_limit_reached_error.rb +24 -0
  97. data/test/test_mechanize_redirect_not_get_or_head_error.rb +3 -7
  98. data/test/test_mechanize_subclass.rb +2 -2
  99. data/test/test_mechanize_util.rb +24 -13
  100. data/test/test_multi_select.rb +23 -22
  101. metadata +145 -114
  102. metadata.gz.sig +0 -0
  103. data/lib/mechanize/inspect.rb +0 -88
  104. data/test/helper.rb +0 -175
  105. data/test/htdocs/form_select_all.html +0 -16
  106. data/test/htdocs/form_select_none.html +0 -17
  107. data/test/htdocs/form_select_noopts.html +0 -10
  108. data/test/htdocs/iframe_test.html +0 -16
  109. data/test/htdocs/nofollow.html +0 -9
  110. data/test/htdocs/norobots.html +0 -8
  111. data/test/htdocs/rel_nofollow.html +0 -8
  112. data/test/htdocs/tc_base_images.html +0 -10
  113. data/test/htdocs/tc_images.html +0 -8
  114. data/test/htdocs/tc_no_attributes.html +0 -16
  115. data/test/htdocs/tc_radiobuttons.html +0 -17
  116. data/test/htdocs/test_bad_encoding.html +0 -52
  117. data/test/servlets.rb +0 -402
  118. data/test/ssl_server.rb +0 -48
  119. data/test/test_cookies.rb +0 -129
  120. data/test/test_form_action.rb +0 -52
  121. data/test/test_form_as_hash.rb +0 -59
  122. data/test/test_form_button.rb +0 -46
  123. data/test/test_frames.rb +0 -34
  124. data/test/test_history.rb +0 -118
  125. data/test/test_history_added.rb +0 -16
  126. data/test/test_html_unscape_forms.rb +0 -46
  127. data/test/test_if_modified_since.rb +0 -20
  128. data/test/test_images.rb +0 -19
  129. data/test/test_no_attributes.rb +0 -13
  130. data/test/test_option.rb +0 -18
  131. data/test/test_pluggable_parser.rb +0 -136
  132. data/test/test_post_form.rb +0 -37
  133. data/test/test_pretty_print.rb +0 -22
  134. data/test/test_radiobutton.rb +0 -75
  135. data/test/test_redirect_limit_reached.rb +0 -39
  136. data/test/test_referer.rb +0 -81
  137. data/test/test_relative_links.rb +0 -40
  138. data/test/test_request.rb +0 -13
  139. data/test/test_response_code.rb +0 -53
  140. data/test/test_robots.rb +0 -72
  141. data/test/test_save_file.rb +0 -48
  142. data/test/test_scheme.rb +0 -48
  143. data/test/test_select.rb +0 -119
  144. data/test/test_select_all.rb +0 -15
  145. data/test/test_select_none.rb +0 -15
  146. data/test/test_select_noopts.rb +0 -18
  147. data/test/test_set_fields.rb +0 -44
  148. data/test/test_ssl_server.rb +0 -20
@@ -1,9 +1,6 @@
1
- class Mechanize
2
- class Form
3
- # This class represents a Submit button in a form.
4
- class Button < Field ; end
5
- class Submit < Button; end
6
- class Reset < Button; end
7
- end
1
+ ##
2
+ # A Submit button in a Form
3
+
4
+ class Mechanize::Form::Button < Mechanize::Form::Field
8
5
  end
9
6
 
@@ -1,11 +1,12 @@
1
- class Mechanize
2
- class Form
3
- # This class represents a check box found in a Form. To activate the
4
- # CheckBox in the Form, set the checked method to true.
5
- class CheckBox < RadioButton
6
- def query_value
7
- [[@name, @value || "on"]]
8
- end
9
- end
1
+ ##
2
+ # This class represents a check box found in a Form. To activate the CheckBox
3
+ # in the Form, set the checked method to true.
4
+
5
+ class Mechanize::Form::CheckBox < Mechanize::Form::RadioButton
6
+
7
+ def query_value
8
+ [[@name, @value || "on"]]
10
9
  end
10
+
11
11
  end
12
+
@@ -1,44 +1,54 @@
1
- class Mechanize
2
- class Form
3
- # This class represents a field in a form. It handles the following input
4
- # tags found in a form:
5
- # text, password, hidden, int, textarea
6
- #
7
- # To set the value of a field, just use the value method:
8
- # field.value = "foo"
9
- class Field
10
- attr_accessor :name, :value, :node
11
-
12
- def initialize node, value = node['value']
13
- @node = node
14
- @name = Util.html_unescape(node['name'])
15
- @value = if value.is_a? String
16
- Util.html_unescape(value)
17
- else
18
- value
19
- end
20
- end
21
-
22
- def query_value
23
- [[@name, @value || '']]
24
- end
25
-
26
- def <=> other
27
- return 0 if self == other
28
- return 1 if Hash === node
29
- return -1 if Hash === other.node
30
- node <=> other.node
31
- end
32
-
33
- # This method is a shortcut to get field's DOM id.
34
- # Common usage: form.field_with(:dom_id => "foo")
35
- def dom_id
36
- node['id']
37
- end
38
- end
39
-
40
- class Text < Field; end
41
- class Textarea < Field; end
42
- class Hidden < Field; end
1
+ ##
2
+ # This class represents a field in a form. It handles the following input
3
+ # tags found in a form:
4
+ #
5
+ # * text
6
+ # * password
7
+ # * hidden
8
+ # * int
9
+ # * textarea
10
+ # * keygen
11
+ #
12
+ # To set the value of a field, just use the value method:
13
+ #
14
+ # field.value = "foo"
15
+
16
+ class Mechanize::Form::Field
17
+ attr_accessor :name, :value, :node, :type
18
+
19
+ def initialize node, value = node['value']
20
+ @node = node
21
+ @name = Mechanize::Util.html_unescape(node['name'])
22
+ @value = if value.is_a? String
23
+ Mechanize::Util.html_unescape(value)
24
+ else
25
+ value
26
+ end
27
+
28
+ @type = node['type']
29
+ end
30
+
31
+ def query_value
32
+ [[@name, @value || '']]
33
+ end
34
+
35
+ def <=> other
36
+ return 0 if self == other
37
+ return 1 if Hash === node
38
+ return -1 if Hash === other.node
39
+ node <=> other.node
40
+ end
41
+
42
+ # This method is a shortcut to get field's DOM id.
43
+ # Common usage: form.field_with(:dom_id => "foo")
44
+ def dom_id
45
+ node['id']
46
+ end
47
+
48
+ # This method is a shortcut to get field's DOM id.
49
+ # Common usage: form.field_with(:dom_class => "foo")
50
+ def dom_class
51
+ node['class']
43
52
  end
44
53
  end
54
+
@@ -1,23 +1,21 @@
1
- class Mechanize
2
- class Form
3
- # This class represents a file upload field found in a form. To use this
4
- # class, set FileUpload#file_data= to the data of the file you want
5
- # to upload and FileUpload#mime_type= to the appropriate mime type
6
- # of the file.
7
- # See the example in EXAMPLES[link://files/EXAMPLES_txt.html]
8
- class FileUpload < Field
9
- attr_accessor :file_name # File name
10
- attr_accessor :mime_type # Mime Type (Optional)
1
+ # This class represents a file upload field found in a form. To use this
2
+ # class, set FileUpload#file_data= to the data of the file you want to upload
3
+ # and FileUpload#mime_type= to the appropriate mime type of the file.
4
+ #
5
+ # See the example in EXAMPLES
11
6
 
12
- alias :file_data :value
13
- alias :file_data= :value=
7
+ class Mechanize::Form::FileUpload < Mechanize::Form::Field
8
+ attr_accessor :file_name # File name
9
+ attr_accessor :mime_type # Mime Type (Optional)
14
10
 
15
- def initialize node, file_name
16
- @file_name = Util.html_unescape(file_name)
17
- @file_data = nil
18
- @node = node
19
- super(node, @file_data)
20
- end
21
- end
11
+ alias :file_data :value
12
+ alias :file_data= :value=
13
+
14
+ def initialize node, file_name
15
+ @file_name = Mechanize::Util.html_unescape(file_name)
16
+ @file_data = nil
17
+ @node = node
18
+ super(node, @file_data)
22
19
  end
23
20
  end
21
+
@@ -0,0 +1,3 @@
1
+ class Mechanize::Form::Hidden < Mechanize::Form::Field
2
+ end
3
+
@@ -1,20 +1,19 @@
1
- class Mechanize
2
- class Form
3
- # This class represents an image button in a form. Use the x and y methods
4
- # to set the x and y positions for where the mouse "clicked".
5
- class ImageButton < Button
6
- attr_accessor :x, :y
1
+ ##
2
+ # This class represents an image button in a form. Use the x and y methods to
3
+ # set the x and y positions for where the mouse "clicked".
7
4
 
8
- def initialize *args
9
- @x = nil
10
- @y = nil
11
- super
12
- end
5
+ class Mechanize::Form::ImageButton < Mechanize::Form::Button
6
+ attr_accessor :x, :y
13
7
 
14
- def query_value
15
- [["#{@name}.x", (@x || 0).to_s],
16
- ["#{@name}.y", (@y || 0).to_s]]
17
- end
18
- end
8
+ def initialize *args
9
+ @x = nil
10
+ @y = nil
11
+ super
12
+ end
13
+
14
+ def query_value
15
+ [["#{@name}.x", (@x || 0).to_s],
16
+ ["#{@name}.y", (@y || 0).to_s]]
19
17
  end
20
18
  end
19
+
@@ -0,0 +1,34 @@
1
+ ##
2
+ # This class represents a keygen (public / private key generator) found in a
3
+ # Form. The field will automatically generate a key pair and compute its own
4
+ # value to match the challenge. Call key to access the public/private key
5
+ # pair.
6
+
7
+ class Mechanize::Form::Keygen < Mechanize::Form::Field
8
+ # The challenge for this <keygen>.
9
+ attr_reader :challenge
10
+
11
+ # The key associated with this <keygen> tag.
12
+ attr_reader :key
13
+
14
+ def initialize(node, value = nil)
15
+ super
16
+ @challenge = node['challenge']
17
+
18
+ @spki = OpenSSL::Netscape::SPKI.new
19
+ @spki.challenge = @challenge
20
+
21
+ @key = nil
22
+ generate_key if value.nil? || value.empty?
23
+ end
24
+
25
+ # Generates a key pair and sets the field's value.
26
+ def generate_key(key_size = 2048)
27
+ # Spec at http://dev.w3.org/html5/spec/Overview.html#the-keygen-element
28
+ @key = OpenSSL::PKey::RSA.new key_size
29
+ @spki.public_key = @key.public_key
30
+ @spki.sign @key, OpenSSL::Digest::MD5.new
31
+ self.value = @spki.to_pem
32
+ end
33
+ end
34
+
@@ -1,15 +1,18 @@
1
+ ##
1
2
  # This class represents a select list where multiple values can be selected.
2
3
  # MultiSelectList#value= accepts an array, and those values are used as
3
4
  # values for the select list. For example, to select multiple values,
4
5
  # simply do this:
5
6
  #
6
- # list.value = ['one', 'two']
7
+ # list.value = ['one', 'two']
7
8
  #
8
9
  # Single values are still supported, so these two are the same:
9
10
  #
10
- # list.value = ['one']
11
- # list.value = 'one'
11
+ # list.value = ['one']
12
+ # list.value = 'one'
13
+
12
14
  class Mechanize::Form::MultiSelectList < Mechanize::Form::Field
15
+
13
16
  extend Mechanize::ElementMatcher
14
17
 
15
18
  attr_accessor :options
@@ -20,20 +23,28 @@ class Mechanize::Form::MultiSelectList < Mechanize::Form::Field
20
23
 
21
24
  # parse
22
25
  node.search('option').each do |n|
23
- option = Mechanize::Form::Option.new(n, self)
24
- @options << option
26
+ @options << Mechanize::Form::Option.new(n, self)
25
27
  end
26
- super(node, value)
28
+
29
+ super node, value
27
30
  end
28
31
 
29
32
  ##
33
+ # :method: option_with
34
+ #
30
35
  # Find one option on this select list with +criteria+
36
+ #
31
37
  # Example:
38
+ #
32
39
  # select_list.option_with(:value => '1').value = 'foo'
33
40
 
34
41
  ##
42
+ # :method: options_with
43
+ #
35
44
  # Find all options on this select list with +criteria+
45
+ #
36
46
  # Example:
47
+ #
37
48
  # select_list.options_with(:value => /1|2/).each do |field|
38
49
  # field.value = '20'
39
50
  # end
@@ -41,7 +52,7 @@ class Mechanize::Form::MultiSelectList < Mechanize::Form::Field
41
52
  elements_with :option
42
53
 
43
54
  def query_value
44
- value ? value.collect { |v| [name, v] } : ''
55
+ value ? value.map { |v| [name, v] } : ''
45
56
  end
46
57
 
47
58
  # Select no options
@@ -75,8 +86,8 @@ class Mechanize::Form::MultiSelectList < Mechanize::Form::Field
75
86
 
76
87
  def value
77
88
  value = []
78
- value.push(*@value)
79
- value.push(*selected_options.collect { |o| o.value })
89
+ value.concat @value
90
+ value.concat selected_options.map { |o| o.value }
80
91
  value
81
92
  end
82
93
 
@@ -1,49 +1,50 @@
1
- class Mechanize
2
- class Form
3
- # This class contains option an option found within SelectList. A
4
- # SelectList can have many Option classes associated with it. An option
5
- # can be selected by calling Option#tick, or Option#click. For example,
6
- # select the first option in a list:
7
- # select_list.first.tick
8
- class Option
9
- attr_reader :value, :selected, :text, :select_list
10
-
11
- alias :to_s :value
12
- alias :selected? :selected
13
-
14
- def initialize(node, select_list)
15
- @text = node.inner_text
16
- @value = Util.html_unescape(node['value'] || node.inner_text)
17
- @selected = node.has_attribute? 'selected'
18
- @select_list = select_list # The select list this option belongs to
19
- end
20
-
21
- # Select this option
22
- def select
23
- unselect_peers
24
- @selected = true
25
- end
26
-
27
- # Unselect this option
28
- def unselect
29
- @selected = false
30
- end
31
-
32
- alias :tick :select
33
- alias :untick :unselect
34
-
35
- # Toggle the selection value of this option
36
- def click
37
- unselect_peers
38
- @selected = !@selected
39
- end
40
-
41
- private
42
- def unselect_peers
43
- if @select_list.instance_of? SelectList
44
- @select_list.select_none
45
- end
46
- end
47
- end
1
+ ##
2
+ # This class contains an option found within SelectList. A SelectList can
3
+ # have many Option classes associated with it. An option can be selected by
4
+ # calling Option#tick, or Option#click.
5
+ #
6
+ # To select the first option in a list:
7
+ #
8
+ # select_list.first.tick
9
+
10
+ class Mechanize::Form::Option
11
+ attr_reader :value, :selected, :text, :select_list
12
+
13
+ alias :to_s :value
14
+ alias :selected? :selected
15
+
16
+ def initialize(node, select_list)
17
+ @text = node.inner_text
18
+ @value = Mechanize::Util.html_unescape(node['value'] || node.inner_text)
19
+ @selected = node.has_attribute? 'selected'
20
+ @select_list = select_list # The select list this option belongs to
21
+ end
22
+
23
+ # Select this option
24
+ def select
25
+ unselect_peers
26
+ @selected = true
27
+ end
28
+
29
+ # Unselect this option
30
+ def unselect
31
+ @selected = false
32
+ end
33
+
34
+ alias :tick :select
35
+ alias :untick :unselect
36
+
37
+ # Toggle the selection value of this option
38
+ def click
39
+ unselect_peers
40
+ @selected = !@selected
41
+ end
42
+
43
+ private
44
+ def unselect_peers
45
+ return unless Mechanize::Form::SelectList === @select_list
46
+
47
+ @select_list.select_none
48
48
  end
49
49
  end
50
+
@@ -1,48 +1,55 @@
1
- class Mechanize
2
- class Form
3
- # This class represents a radio button found in a Form. To activate the
4
- # RadioButton in the Form, set the checked method to true.
5
- class RadioButton < Field
6
- attr_accessor :checked
7
-
8
- def initialize node, form
9
- @checked = !!node['checked']
10
- @form = form
11
- super(node)
12
- end
13
-
14
- def check
15
- uncheck_peers
16
- @checked = true
17
- end
18
-
19
- def uncheck
20
- @checked = false
21
- end
22
-
23
- def click
24
- checked ? uncheck : check
25
- end
26
-
27
- def label
28
- (id = self['id']) && @form.page.labels_hash[id] || nil
29
- end
30
-
31
- def text
32
- label.text rescue nil
33
- end
34
-
35
- def [](key)
36
- @node[key]
37
- end
38
-
39
- private
40
- def uncheck_peers
41
- @form.radiobuttons_with(:name => name).each do |b|
42
- next if b.value == value
43
- b.uncheck
44
- end
45
- end
1
+ ##
2
+ # This class represents a radio button found in a Form. To activate the
3
+ # RadioButton in the Form, set the checked method to true.
4
+
5
+ class Mechanize::Form::RadioButton < Mechanize::Form::Field
6
+ attr_accessor :checked
7
+
8
+ def initialize node, form
9
+ @checked = !!node['checked']
10
+ @form = form
11
+ super(node)
12
+ end
13
+
14
+ def check
15
+ uncheck_peers
16
+ @checked = true
17
+ end
18
+
19
+ alias checked? checked
20
+
21
+ def uncheck
22
+ @checked = false
23
+ end
24
+
25
+ def click
26
+ checked ? uncheck : check
27
+ end
28
+
29
+ def label
30
+ (id = self['id']) && @form.page.labels_hash[id] || nil
31
+ end
32
+
33
+ def text
34
+ label.text rescue nil
35
+ end
36
+
37
+ def [](key)
38
+ @node[key]
39
+ end
40
+
41
+ def pretty_print_instance_variables # :nodoc:
42
+ [:@checked, :@name, :@value]
43
+ end
44
+
45
+ private
46
+
47
+ def uncheck_peers
48
+ @form.radiobuttons_with(:name => name).each do |b|
49
+ next if b.value == value
50
+ b.uncheck
46
51
  end
47
52
  end
53
+
48
54
  end
55
+