tenderlove-mechanize 0.9.3.20090623142847 → 0.9.3.20090911221705

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 (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
@@ -0,0 +1,9 @@
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
8
+ end
9
+
@@ -0,0 +1,11 @@
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
10
+ end
11
+ end
@@ -0,0 +1,30 @@
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
11
+
12
+ def initialize(name, value)
13
+ @name = Util.html_unescape(name)
14
+ @value = if value.is_a? String
15
+ Util.html_unescape(value)
16
+ else
17
+ value
18
+ end
19
+ end
20
+
21
+ def query_value
22
+ [[@name, @value || '']]
23
+ end
24
+ end
25
+
26
+ class Text < Field; end
27
+ class Textarea < Field; end
28
+ class Hidden < Field; end
29
+ end
30
+ end
@@ -0,0 +1,22 @@
1
+ class Mechanize
2
+ class Form
3
+ # This class represents a file upload field found in a form. To use this
4
+ # class, set WWW::FileUpload#file_data= to the data of the file you want
5
+ # to upload and WWW::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)
11
+
12
+ alias :file_data :value
13
+ alias :file_data= :value=
14
+
15
+ def initialize(name, file_name)
16
+ @file_name = Util.html_unescape(file_name)
17
+ @file_data = nil
18
+ super(name, @file_data)
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,21 @@
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
7
+
8
+ def initialize(name, value)
9
+ @x = nil
10
+ @y = nil
11
+ super(name, value)
12
+ end
13
+
14
+ def query_value
15
+ super <<
16
+ [@name + ".x", (@x || 0).to_s] <<
17
+ [@name + ".y", (@y || 0).to_s]
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,67 @@
1
+ class Mechanize
2
+ class Form
3
+ # This class represents a select list where multiple values can be selected.
4
+ # MultiSelectList#value= accepts an array, and those values are used as
5
+ # values for the select list. For example, to select multiple values,
6
+ # simply do this:
7
+ # list.value = ['one', 'two']
8
+ # Single values are still supported, so these two are the same:
9
+ # list.value = ['one']
10
+ # list.value = 'one'
11
+ class MultiSelectList < Field
12
+ attr_accessor :options
13
+
14
+ def initialize(name, node)
15
+ value = []
16
+ @options = []
17
+
18
+ # parse
19
+ node.search('option').each do |n|
20
+ option = Option.new(n, self)
21
+ @options << option
22
+ end
23
+ super(name, value)
24
+ end
25
+
26
+ def query_value
27
+ value ? value.collect { |v| [name, v] } : ''
28
+ end
29
+
30
+ # Select no options
31
+ def select_none
32
+ @value = []
33
+ options.each { |o| o.untick }
34
+ end
35
+
36
+ # Select all options
37
+ def select_all
38
+ @value = []
39
+ options.each { |o| o.tick }
40
+ end
41
+
42
+ # Get a list of all selected options
43
+ def selected_options
44
+ @options.find_all { |o| o.selected? }
45
+ end
46
+
47
+ def value=(values)
48
+ select_none
49
+ [values].flatten.each do |value|
50
+ option = options.find { |o| o.value == value }
51
+ if option.nil?
52
+ @value.push(value)
53
+ else
54
+ option.select
55
+ end
56
+ end
57
+ end
58
+
59
+ def value
60
+ value = []
61
+ value.push(*@value)
62
+ value.push(*selected_options.collect { |o| o.value })
63
+ value
64
+ end
65
+ end
66
+ end
67
+ end
@@ -0,0 +1,49 @@
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
48
+ end
49
+ end
@@ -0,0 +1,49 @@
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(name, value, checked, form, node)
9
+ @checked = checked
10
+ @form = form
11
+ @node = node
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
+ def label
29
+ (id = self['id']) && @form.page.labels_hash[id] || nil
30
+ end
31
+
32
+ def text
33
+ label.text rescue nil
34
+ end
35
+
36
+ def [](key)
37
+ @node[key]
38
+ end
39
+
40
+ private
41
+ def uncheck_peers
42
+ @form.radiobuttons_with(:name => name).each do |b|
43
+ next if b.value == value
44
+ b.uncheck
45
+ end
46
+ end
47
+ end
48
+ end
49
+ end
@@ -0,0 +1,43 @@
1
+ class Mechanize
2
+ class Form
3
+ # This class represents a select list or drop down box in a Form. Set the
4
+ # value for the list by calling SelectList#value=. SelectList contains a
5
+ # list of Option that were found. After finding the correct option, set
6
+ # the select lists value to the option value:
7
+ # selectlist.value = selectlist.options.first.value
8
+ # Options can also be selected by "clicking" or selecting them. See Option
9
+ class SelectList < MultiSelectList
10
+ def initialize(name, node)
11
+ super(name, node)
12
+ if selected_options.length > 1
13
+ selected_options.reverse[1..selected_options.length].each do |o|
14
+ o.unselect
15
+ end
16
+ end
17
+ end
18
+
19
+ def value
20
+ value = super
21
+ if value.length > 0
22
+ value.last
23
+ elsif @options.length > 0
24
+ @options.first.value
25
+ else
26
+ nil
27
+ end
28
+ end
29
+
30
+ def value=(new)
31
+ if new != new.to_s and new.respond_to? :first
32
+ super([new.first])
33
+ else
34
+ super([new.to_s])
35
+ end
36
+ end
37
+
38
+ def query_value
39
+ value ? [[name, value]] : nil
40
+ end
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,11 @@
1
+ class Mechanize
2
+ class Headers < Hash
3
+ def [](key)
4
+ super(key.downcase)
5
+ end
6
+ def []=(key, value)
7
+ super(key.downcase, value)
8
+ end
9
+ end
10
+ end
11
+
@@ -0,0 +1,65 @@
1
+ class Mechanize
2
+ ##
3
+ # This class manages history for your mechanize object.
4
+ class History < Array
5
+ attr_accessor :max_size
6
+
7
+ def initialize(max_size = nil)
8
+ @max_size = max_size
9
+ @history_index = {}
10
+ end
11
+
12
+ def initialize_copy(orig)
13
+ super
14
+ @history_index = orig.instance_variable_get(:@history_index).dup
15
+ end
16
+
17
+ def push(page, uri = nil)
18
+ super(page)
19
+ @history_index[(uri ? uri : page.uri).to_s] = page
20
+ if @max_size && self.length > @max_size
21
+ while self.length > @max_size
22
+ self.shift
23
+ end
24
+ end
25
+ self
26
+ end
27
+ alias :<< :push
28
+
29
+ def visited?(url)
30
+ ! visited_page(url).nil?
31
+ end
32
+
33
+ def visited_page(url)
34
+ @history_index[(url.respond_to?(:uri) ? url.uri : url).to_s]
35
+ end
36
+
37
+ def clear
38
+ @history_index.clear
39
+ super
40
+ end
41
+
42
+ def shift
43
+ return nil if length == 0
44
+ page = self[0]
45
+ self[0] = nil
46
+ super
47
+ remove_from_index(page)
48
+ page
49
+ end
50
+
51
+ def pop
52
+ return nil if length == 0
53
+ page = super
54
+ remove_from_index(page)
55
+ page
56
+ end
57
+
58
+ private
59
+ def remove_from_index(page)
60
+ @history_index.each do |k,v|
61
+ @history_index.delete(k) if v == page
62
+ end
63
+ end
64
+ end
65
+ end
@@ -0,0 +1,88 @@
1
+ require 'pp'
2
+
3
+ # :stopdoc:
4
+ class Mechanize
5
+ def pretty_print(q)
6
+ q.object_group(self) {
7
+ q.breakable
8
+ q.pp cookie_jar
9
+ q.breakable
10
+ q.pp current_page
11
+ }
12
+ end
13
+
14
+ class Page
15
+ def pretty_print(q)
16
+ q.object_group(self) {
17
+ q.breakable
18
+ q.group(1, '{url', '}') {q.breakable; q.pp uri }
19
+ q.breakable
20
+ q.group(1, '{meta', '}') {
21
+ meta.each { |link| q.breakable; q.pp link }
22
+ }
23
+ q.breakable
24
+ q.group(1, '{title', '}') { q.breakable; q.pp title }
25
+ q.breakable
26
+ q.group(1, '{iframes', '}') {
27
+ iframes.each { |link| q.breakable; q.pp link }
28
+ }
29
+ q.breakable
30
+ q.group(1, '{frames', '}') {
31
+ frames.each { |link| q.breakable; q.pp link }
32
+ }
33
+ q.breakable
34
+ q.group(1, '{links', '}') {
35
+ links.each { |link| q.breakable; q.pp link }
36
+ }
37
+ q.breakable
38
+ q.group(1, '{forms', '}') {
39
+ forms.each { |form| q.breakable; q.pp form }
40
+ }
41
+ }
42
+ end
43
+
44
+ class Link
45
+ def pretty_print(q)
46
+ q.object_group(self) {
47
+ q.breakable; q.pp text
48
+ q.breakable; q.pp href
49
+ }
50
+ end
51
+ end
52
+ end
53
+
54
+ class Form
55
+ def pretty_print(q)
56
+ q.object_group(self) {
57
+ q.breakable; q.group(1, '{name', '}') { q.breakable; q.pp name }
58
+ q.breakable; q.group(1, '{method', '}') { q.breakable; q.pp method }
59
+ q.breakable; q.group(1, '{action', '}') { q.breakable; q.pp action }
60
+ q.breakable; q.group(1, '{fields', '}') {
61
+ fields.each do |field|
62
+ q.breakable
63
+ q.pp field
64
+ end
65
+ }
66
+ q.breakable; q.group(1, '{radiobuttons', '}') {
67
+ radiobuttons.each { |b| q.breakable; q.pp b }
68
+ }
69
+ q.breakable; q.group(1, '{checkboxes', '}') {
70
+ checkboxes.each { |b| q.breakable; q.pp b }
71
+ }
72
+ q.breakable; q.group(1, '{file_uploads', '}') {
73
+ file_uploads.each { |b| q.breakable; q.pp b }
74
+ }
75
+ q.breakable; q.group(1, '{buttons', '}') {
76
+ buttons.each { |b| q.breakable; q.pp b }
77
+ }
78
+ }
79
+ end
80
+
81
+ class RadioButton
82
+ def pretty_print_instance_variables
83
+ [:@checked, :@name, :@value]
84
+ end
85
+ end
86
+ end
87
+ end
88
+ # :startdoc: