knu-mechanize 0.9.3.20090623142847

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.
Files changed (173) hide show
  1. data/CHANGELOG.rdoc +504 -0
  2. data/EXAMPLES.rdoc +171 -0
  3. data/FAQ.rdoc +11 -0
  4. data/GUIDE.rdoc +122 -0
  5. data/LICENSE.rdoc +340 -0
  6. data/Manifest.txt +169 -0
  7. data/README.rdoc +60 -0
  8. data/Rakefile +43 -0
  9. data/examples/flickr_upload.rb +23 -0
  10. data/examples/mech-dump.rb +7 -0
  11. data/examples/proxy_req.rb +9 -0
  12. data/examples/rubyforge.rb +21 -0
  13. data/examples/spider.rb +11 -0
  14. data/lib/mechanize.rb +7 -0
  15. data/lib/www/mechanize.rb +619 -0
  16. data/lib/www/mechanize/chain.rb +34 -0
  17. data/lib/www/mechanize/chain/auth_headers.rb +80 -0
  18. data/lib/www/mechanize/chain/body_decoding_handler.rb +48 -0
  19. data/lib/www/mechanize/chain/connection_resolver.rb +78 -0
  20. data/lib/www/mechanize/chain/custom_headers.rb +23 -0
  21. data/lib/www/mechanize/chain/handler.rb +9 -0
  22. data/lib/www/mechanize/chain/header_resolver.rb +53 -0
  23. data/lib/www/mechanize/chain/parameter_resolver.rb +24 -0
  24. data/lib/www/mechanize/chain/post_connect_hook.rb +0 -0
  25. data/lib/www/mechanize/chain/pre_connect_hook.rb +22 -0
  26. data/lib/www/mechanize/chain/request_resolver.rb +32 -0
  27. data/lib/www/mechanize/chain/response_body_parser.rb +40 -0
  28. data/lib/www/mechanize/chain/response_header_handler.rb +50 -0
  29. data/lib/www/mechanize/chain/response_reader.rb +41 -0
  30. data/lib/www/mechanize/chain/ssl_resolver.rb +42 -0
  31. data/lib/www/mechanize/chain/uri_resolver.rb +77 -0
  32. data/lib/www/mechanize/content_type_error.rb +16 -0
  33. data/lib/www/mechanize/cookie.rb +72 -0
  34. data/lib/www/mechanize/cookie_jar.rb +191 -0
  35. data/lib/www/mechanize/file.rb +73 -0
  36. data/lib/www/mechanize/file_response.rb +62 -0
  37. data/lib/www/mechanize/file_saver.rb +39 -0
  38. data/lib/www/mechanize/form.rb +360 -0
  39. data/lib/www/mechanize/form/button.rb +8 -0
  40. data/lib/www/mechanize/form/check_box.rb +13 -0
  41. data/lib/www/mechanize/form/field.rb +28 -0
  42. data/lib/www/mechanize/form/file_upload.rb +24 -0
  43. data/lib/www/mechanize/form/image_button.rb +23 -0
  44. data/lib/www/mechanize/form/multi_select_list.rb +69 -0
  45. data/lib/www/mechanize/form/option.rb +51 -0
  46. data/lib/www/mechanize/form/radio_button.rb +38 -0
  47. data/lib/www/mechanize/form/select_list.rb +45 -0
  48. data/lib/www/mechanize/headers.rb +12 -0
  49. data/lib/www/mechanize/history.rb +67 -0
  50. data/lib/www/mechanize/inspect.rb +90 -0
  51. data/lib/www/mechanize/monkey_patch.rb +37 -0
  52. data/lib/www/mechanize/page.rb +181 -0
  53. data/lib/www/mechanize/page/base.rb +10 -0
  54. data/lib/www/mechanize/page/frame.rb +22 -0
  55. data/lib/www/mechanize/page/link.rb +50 -0
  56. data/lib/www/mechanize/page/meta.rb +51 -0
  57. data/lib/www/mechanize/pluggable_parsers.rb +103 -0
  58. data/lib/www/mechanize/redirect_limit_reached_error.rb +18 -0
  59. data/lib/www/mechanize/redirect_not_get_or_head_error.rb +20 -0
  60. data/lib/www/mechanize/response_code_error.rb +25 -0
  61. data/lib/www/mechanize/unsupported_scheme_error.rb +10 -0
  62. data/lib/www/mechanize/util.rb +76 -0
  63. data/mechanize.gemspec +41 -0
  64. data/test/chain/test_argument_validator.rb +14 -0
  65. data/test/chain/test_auth_headers.rb +25 -0
  66. data/test/chain/test_custom_headers.rb +18 -0
  67. data/test/chain/test_header_resolver.rb +28 -0
  68. data/test/chain/test_parameter_resolver.rb +35 -0
  69. data/test/chain/test_request_resolver.rb +29 -0
  70. data/test/chain/test_response_reader.rb +24 -0
  71. data/test/data/htpasswd +1 -0
  72. data/test/data/server.crt +16 -0
  73. data/test/data/server.csr +12 -0
  74. data/test/data/server.key +15 -0
  75. data/test/data/server.pem +15 -0
  76. data/test/helper.rb +129 -0
  77. data/test/htdocs/alt_text.html +10 -0
  78. data/test/htdocs/bad_form_test.html +9 -0
  79. data/test/htdocs/button.jpg +0 -0
  80. data/test/htdocs/empty_form.html +6 -0
  81. data/test/htdocs/file_upload.html +26 -0
  82. data/test/htdocs/find_link.html +41 -0
  83. data/test/htdocs/form_multi_select.html +16 -0
  84. data/test/htdocs/form_multival.html +37 -0
  85. data/test/htdocs/form_no_action.html +18 -0
  86. data/test/htdocs/form_no_input_name.html +16 -0
  87. data/test/htdocs/form_select.html +16 -0
  88. data/test/htdocs/form_select_all.html +16 -0
  89. data/test/htdocs/form_select_none.html +17 -0
  90. data/test/htdocs/form_select_noopts.html +10 -0
  91. data/test/htdocs/form_set_fields.html +14 -0
  92. data/test/htdocs/form_test.html +188 -0
  93. data/test/htdocs/frame_test.html +30 -0
  94. data/test/htdocs/google.html +13 -0
  95. data/test/htdocs/iframe_test.html +16 -0
  96. data/test/htdocs/index.html +6 -0
  97. data/test/htdocs/link with space.html +5 -0
  98. data/test/htdocs/meta_cookie.html +11 -0
  99. data/test/htdocs/no_title_test.html +6 -0
  100. data/test/htdocs/relative/tc_relative_links.html +21 -0
  101. data/test/htdocs/tc_bad_links.html +5 -0
  102. data/test/htdocs/tc_base_link.html +8 -0
  103. data/test/htdocs/tc_blank_form.html +11 -0
  104. data/test/htdocs/tc_checkboxes.html +19 -0
  105. data/test/htdocs/tc_encoded_links.html +5 -0
  106. data/test/htdocs/tc_follow_meta.html +8 -0
  107. data/test/htdocs/tc_form_action.html +48 -0
  108. data/test/htdocs/tc_links.html +18 -0
  109. data/test/htdocs/tc_no_attributes.html +16 -0
  110. data/test/htdocs/tc_pretty_print.html +17 -0
  111. data/test/htdocs/tc_radiobuttons.html +17 -0
  112. data/test/htdocs/tc_referer.html +10 -0
  113. data/test/htdocs/tc_relative_links.html +19 -0
  114. data/test/htdocs/tc_textarea.html +23 -0
  115. data/test/htdocs/unusual______.html +5 -0
  116. data/test/servlets.rb +365 -0
  117. data/test/ssl_server.rb +48 -0
  118. data/test/test_authenticate.rb +71 -0
  119. data/test/test_bad_links.rb +25 -0
  120. data/test/test_blank_form.rb +16 -0
  121. data/test/test_checkboxes.rb +61 -0
  122. data/test/test_content_type.rb +13 -0
  123. data/test/test_cookie_class.rb +338 -0
  124. data/test/test_cookie_jar.rb +362 -0
  125. data/test/test_cookies.rb +123 -0
  126. data/test/test_encoded_links.rb +20 -0
  127. data/test/test_errors.rb +49 -0
  128. data/test/test_follow_meta.rb +108 -0
  129. data/test/test_form_action.rb +52 -0
  130. data/test/test_form_as_hash.rb +61 -0
  131. data/test/test_form_button.rb +38 -0
  132. data/test/test_form_no_inputname.rb +15 -0
  133. data/test/test_forms.rb +564 -0
  134. data/test/test_frames.rb +25 -0
  135. data/test/test_get_headers.rb +52 -0
  136. data/test/test_gzipping.rb +22 -0
  137. data/test/test_hash_api.rb +45 -0
  138. data/test/test_history.rb +142 -0
  139. data/test/test_history_added.rb +16 -0
  140. data/test/test_html_unscape_forms.rb +39 -0
  141. data/test/test_if_modified_since.rb +20 -0
  142. data/test/test_keep_alive.rb +31 -0
  143. data/test/test_links.rb +120 -0
  144. data/test/test_mech.rb +268 -0
  145. data/test/test_mechanize_file.rb +47 -0
  146. data/test/test_meta.rb +65 -0
  147. data/test/test_multi_select.rb +106 -0
  148. data/test/test_no_attributes.rb +13 -0
  149. data/test/test_option.rb +18 -0
  150. data/test/test_page.rb +119 -0
  151. data/test/test_pluggable_parser.rb +145 -0
  152. data/test/test_post_form.rb +34 -0
  153. data/test/test_pretty_print.rb +22 -0
  154. data/test/test_radiobutton.rb +75 -0
  155. data/test/test_redirect_limit_reached.rb +41 -0
  156. data/test/test_redirect_verb_handling.rb +45 -0
  157. data/test/test_referer.rb +39 -0
  158. data/test/test_relative_links.rb +40 -0
  159. data/test/test_request.rb +13 -0
  160. data/test/test_response_code.rb +52 -0
  161. data/test/test_save_file.rb +48 -0
  162. data/test/test_scheme.rb +48 -0
  163. data/test/test_select.rb +106 -0
  164. data/test/test_select_all.rb +15 -0
  165. data/test/test_select_none.rb +15 -0
  166. data/test/test_select_noopts.rb +16 -0
  167. data/test/test_set_fields.rb +44 -0
  168. data/test/test_ssl_server.rb +20 -0
  169. data/test/test_subclass.rb +14 -0
  170. data/test/test_textarea.rb +45 -0
  171. data/test/test_upload.rb +109 -0
  172. data/test/test_verbs.rb +25 -0
  173. metadata +314 -0
@@ -0,0 +1,8 @@
1
+ module WWW
2
+ class Mechanize
3
+ class Form
4
+ # This class represents a Submit button in a form.
5
+ class Button < Field; end
6
+ end
7
+ end
8
+ end
@@ -0,0 +1,13 @@
1
+ module WWW
2
+ class Mechanize
3
+ class Form
4
+ # This class represents a check box found in a Form. To activate the
5
+ # CheckBox in the Form, set the checked method to true.
6
+ class CheckBox < RadioButton
7
+ def query_value
8
+ [[@name, @value || "on"]]
9
+ end
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,28 @@
1
+ module WWW
2
+ class Mechanize
3
+ class Form
4
+ # This class represents a field in a form. It handles the following input
5
+ # tags found in a form:
6
+ # text, password, hidden, int, textarea
7
+ #
8
+ # To set the value of a field, just use the value method:
9
+ # field.value = "foo"
10
+ class Field
11
+ attr_accessor :name, :value
12
+
13
+ def initialize(name, value)
14
+ @name = Util.html_unescape(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
+ end
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,24 @@
1
+ module WWW
2
+ class Mechanize
3
+ class Form
4
+ # This class represents a file upload field found in a form. To use this
5
+ # class, set WWW::FileUpload#file_data= to the data of the file you want
6
+ # to upload and WWW::FileUpload#mime_type= to the appropriate mime type
7
+ # of the file.
8
+ # See the example in EXAMPLES[link://files/EXAMPLES_txt.html]
9
+ class FileUpload < Field
10
+ attr_accessor :file_name # File name
11
+ attr_accessor :mime_type # Mime Type (Optional)
12
+
13
+ alias :file_data :value
14
+ alias :file_data= :value=
15
+
16
+ def initialize(name, file_name)
17
+ @file_name = Util.html_unescape(file_name)
18
+ @file_data = nil
19
+ super(name, @file_data)
20
+ end
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,23 @@
1
+ module WWW
2
+ class Mechanize
3
+ class Form
4
+ # This class represents an image button in a form. Use the x and y methods
5
+ # to set the x and y positions for where the mouse "clicked".
6
+ class ImageButton < Button
7
+ attr_accessor :x, :y
8
+
9
+ def initialize(name, value)
10
+ @x = nil
11
+ @y = nil
12
+ super(name, value)
13
+ end
14
+
15
+ def query_value
16
+ super <<
17
+ [@name + ".x", (@x || 0).to_s] <<
18
+ [@name + ".y", (@y || 0).to_s]
19
+ end
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,69 @@
1
+ module WWW
2
+ class Mechanize
3
+ class Form
4
+ # This class represents a select list where multiple values can be selected.
5
+ # MultiSelectList#value= accepts an array, and those values are used as
6
+ # values for the select list. For example, to select multiple values,
7
+ # simply do this:
8
+ # list.value = ['one', 'two']
9
+ # Single values are still supported, so these two are the same:
10
+ # list.value = ['one']
11
+ # list.value = 'one'
12
+ class MultiSelectList < Field
13
+ attr_accessor :options
14
+
15
+ def initialize(name, node)
16
+ value = []
17
+ @options = []
18
+
19
+ # parse
20
+ node.search('option').each do |n|
21
+ option = Option.new(n, self)
22
+ @options << option
23
+ end
24
+ super(name, value)
25
+ end
26
+
27
+ def query_value
28
+ value ? value.collect { |v| [name, v] } : ''
29
+ end
30
+
31
+ # Select no options
32
+ def select_none
33
+ @value = []
34
+ options.each { |o| o.untick }
35
+ end
36
+
37
+ # Select all options
38
+ def select_all
39
+ @value = []
40
+ options.each { |o| o.tick }
41
+ end
42
+
43
+ # Get a list of all selected options
44
+ def selected_options
45
+ @options.find_all { |o| o.selected? }
46
+ end
47
+
48
+ def value=(values)
49
+ select_none
50
+ [values].flatten.each do |value|
51
+ option = options.find { |o| o.value == value }
52
+ if option.nil?
53
+ @value.push(value)
54
+ else
55
+ option.select
56
+ end
57
+ end
58
+ end
59
+
60
+ def value
61
+ value = []
62
+ value.push(*@value)
63
+ value.push(*selected_options.collect { |o| o.value })
64
+ value
65
+ end
66
+ end
67
+ end
68
+ end
69
+ end
@@ -0,0 +1,51 @@
1
+ module WWW
2
+ class Mechanize
3
+ class Form
4
+ # This class contains option an option found within SelectList. A
5
+ # SelectList can have many Option classes associated with it. An option
6
+ # can be selected by calling Option#tick, or Option#click. For example,
7
+ # select the first option in a list:
8
+ # select_list.first.tick
9
+ class Option
10
+ attr_reader :value, :selected, :text, :select_list
11
+
12
+ alias :to_s :value
13
+ alias :selected? :selected
14
+
15
+ def initialize(node, select_list)
16
+ @text = node.inner_text
17
+ @value = Util.html_unescape(node['value'] || node.inner_text)
18
+ @selected = node.has_attribute? 'selected'
19
+ @select_list = select_list # The select list this option belongs to
20
+ end
21
+
22
+ # Select this option
23
+ def select
24
+ unselect_peers
25
+ @selected = true
26
+ end
27
+
28
+ # Unselect this option
29
+ def unselect
30
+ @selected = false
31
+ end
32
+
33
+ alias :tick :select
34
+ alias :untick :unselect
35
+
36
+ # Toggle the selection value of this option
37
+ def click
38
+ unselect_peers
39
+ @selected = !@selected
40
+ end
41
+
42
+ private
43
+ def unselect_peers
44
+ if @select_list.instance_of? SelectList
45
+ @select_list.select_none
46
+ end
47
+ end
48
+ end
49
+ end
50
+ end
51
+ end
@@ -0,0 +1,38 @@
1
+ module WWW
2
+ class Mechanize
3
+ class Form
4
+ # This class represents a radio button found in a Form. To activate the
5
+ # RadioButton in the Form, set the checked method to true.
6
+ class RadioButton < Field
7
+ attr_accessor :checked
8
+
9
+ def initialize(name, value, checked, form)
10
+ @checked = checked
11
+ @form = form
12
+ super(name, value)
13
+ end
14
+
15
+ def check
16
+ uncheck_peers
17
+ @checked = true
18
+ end
19
+
20
+ def uncheck
21
+ @checked = false
22
+ end
23
+
24
+ def click
25
+ checked ? uncheck : check
26
+ end
27
+
28
+ private
29
+ def uncheck_peers
30
+ @form.radiobuttons_with(:name => name).each do |b|
31
+ next if b.value == value
32
+ b.uncheck
33
+ end
34
+ end
35
+ end
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,45 @@
1
+ module WWW
2
+ class Mechanize
3
+ class Form
4
+ # This class represents a select list or drop down box in a Form. Set the
5
+ # value for the list by calling SelectList#value=. SelectList contains a
6
+ # list of Option that were found. After finding the correct option, set
7
+ # the select lists value to the option value:
8
+ # selectlist.value = selectlist.options.first.value
9
+ # Options can also be selected by "clicking" or selecting them. See Option
10
+ class SelectList < MultiSelectList
11
+ def initialize(name, node)
12
+ super(name, node)
13
+ if selected_options.length > 1
14
+ selected_options.reverse[1..selected_options.length].each do |o|
15
+ o.unselect
16
+ end
17
+ end
18
+ end
19
+
20
+ def value
21
+ value = super
22
+ if value.length > 0
23
+ value.last
24
+ elsif @options.length > 0
25
+ @options.first.value
26
+ else
27
+ nil
28
+ end
29
+ end
30
+
31
+ def value=(new)
32
+ if new != new.to_s and new.respond_to? :first
33
+ super([new.first])
34
+ else
35
+ super([new.to_s])
36
+ end
37
+ end
38
+
39
+ def query_value
40
+ value ? [[name, value]] : nil
41
+ end
42
+ end
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,12 @@
1
+ module WWW
2
+ class Mechanize
3
+ class Headers < Hash
4
+ def [](key)
5
+ super(key.downcase)
6
+ end
7
+ def []=(key, value)
8
+ super(key.downcase, value)
9
+ end
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,67 @@
1
+ module WWW
2
+ class Mechanize
3
+ ##
4
+ # This class manages history for your mechanize object.
5
+ class History < Array
6
+ attr_accessor :max_size
7
+
8
+ def initialize(max_size = nil)
9
+ @max_size = max_size
10
+ @history_index = {}
11
+ end
12
+
13
+ def initialize_copy(orig)
14
+ super
15
+ @history_index = orig.instance_variable_get(:@history_index).dup
16
+ end
17
+
18
+ def push(page, uri = nil)
19
+ super(page)
20
+ @history_index[(uri ? uri : page.uri).to_s] = page
21
+ if @max_size && self.length > @max_size
22
+ while self.length > @max_size
23
+ self.shift
24
+ end
25
+ end
26
+ self
27
+ end
28
+ alias :<< :push
29
+
30
+ def visited?(url)
31
+ ! visited_page(url).nil?
32
+ end
33
+
34
+ def visited_page(url)
35
+ @history_index[(url.respond_to?(:uri) ? url.uri : url).to_s]
36
+ end
37
+
38
+ def clear
39
+ @history_index.clear
40
+ super
41
+ end
42
+
43
+ def shift
44
+ return nil if length == 0
45
+ page = self[0]
46
+ self[0] = nil
47
+ super
48
+ remove_from_index(page)
49
+ page
50
+ end
51
+
52
+ def pop
53
+ return nil if length == 0
54
+ page = super
55
+ remove_from_index(page)
56
+ page
57
+ end
58
+
59
+ private
60
+ def remove_from_index(page)
61
+ @history_index.each do |k,v|
62
+ @history_index.delete(k) if v == page
63
+ end
64
+ end
65
+ end
66
+ end
67
+ end
@@ -0,0 +1,90 @@
1
+ require 'pp'
2
+
3
+ module WWW
4
+ # :stopdoc:
5
+ class Mechanize
6
+ def pretty_print(q)
7
+ q.object_group(self) {
8
+ q.breakable
9
+ q.pp cookie_jar
10
+ q.breakable
11
+ q.pp current_page
12
+ }
13
+ end
14
+
15
+ class Page
16
+ def pretty_print(q)
17
+ q.object_group(self) {
18
+ q.breakable
19
+ q.group(1, '{url', '}') {q.breakable; q.pp uri }
20
+ q.breakable
21
+ q.group(1, '{meta', '}') {
22
+ meta.each { |link| q.breakable; q.pp link }
23
+ }
24
+ q.breakable
25
+ q.group(1, '{title', '}') { q.breakable; q.pp title }
26
+ q.breakable
27
+ q.group(1, '{iframes', '}') {
28
+ iframes.each { |link| q.breakable; q.pp link }
29
+ }
30
+ q.breakable
31
+ q.group(1, '{frames', '}') {
32
+ frames.each { |link| q.breakable; q.pp link }
33
+ }
34
+ q.breakable
35
+ q.group(1, '{links', '}') {
36
+ links.each { |link| q.breakable; q.pp link }
37
+ }
38
+ q.breakable
39
+ q.group(1, '{forms', '}') {
40
+ forms.each { |form| q.breakable; q.pp form }
41
+ }
42
+ }
43
+ end
44
+
45
+ class Link
46
+ def pretty_print(q)
47
+ q.object_group(self) {
48
+ q.breakable; q.pp text
49
+ q.breakable; q.pp href
50
+ }
51
+ end
52
+ end
53
+ end
54
+
55
+ class Form
56
+ def pretty_print(q)
57
+ q.object_group(self) {
58
+ q.breakable; q.group(1, '{name', '}') { q.breakable; q.pp name }
59
+ q.breakable; q.group(1, '{method', '}') { q.breakable; q.pp method }
60
+ q.breakable; q.group(1, '{action', '}') { q.breakable; q.pp action }
61
+ q.breakable; q.group(1, '{fields', '}') {
62
+ fields.each do |field|
63
+ q.breakable
64
+ q.pp field
65
+ end
66
+ }
67
+ q.breakable; q.group(1, '{radiobuttons', '}') {
68
+ radiobuttons.each { |b| q.breakable; q.pp b }
69
+ }
70
+ q.breakable; q.group(1, '{checkboxes', '}') {
71
+ checkboxes.each { |b| q.breakable; q.pp b }
72
+ }
73
+ q.breakable; q.group(1, '{file_uploads', '}') {
74
+ file_uploads.each { |b| q.breakable; q.pp b }
75
+ }
76
+ q.breakable; q.group(1, '{buttons', '}') {
77
+ buttons.each { |b| q.breakable; q.pp b }
78
+ }
79
+ }
80
+ end
81
+
82
+ class RadioButton
83
+ def pretty_print_instance_variables
84
+ [:@checked, :@name, :@value]
85
+ end
86
+ end
87
+ end
88
+ end
89
+ # :startdoc:
90
+ end