mechanize 2.7.5 → 2.7.6

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 (40) hide show
  1. checksums.yaml +4 -4
  2. data/.travis.yml +22 -17
  3. data/CHANGELOG.rdoc +12 -0
  4. data/Gemfile +3 -0
  5. data/README.rdoc +1 -1
  6. data/lib/mechanize/element_matcher.rb +4 -1
  7. data/lib/mechanize/form.rb +62 -14
  8. data/lib/mechanize/form/field.rb +46 -0
  9. data/lib/mechanize/form/multi_select_list.rb +3 -7
  10. data/lib/mechanize/form/option.rb +2 -1
  11. data/lib/mechanize/http/agent.rb +37 -24
  12. data/lib/mechanize/http/content_disposition_parser.rb +4 -1
  13. data/lib/mechanize/http/www_authenticate_parser.rb +1 -1
  14. data/lib/mechanize/page.rb +4 -2
  15. data/lib/mechanize/page/frame.rb +2 -0
  16. data/lib/mechanize/parser.rb +3 -3
  17. data/lib/mechanize/test_case/http_refresh_servlet.rb +1 -2
  18. data/lib/mechanize/test_case/infinite_refresh_servlet.rb +1 -2
  19. data/lib/mechanize/version.rb +1 -1
  20. data/mechanize.gemspec +2 -1
  21. data/test/htdocs/find_link.html +1 -4
  22. data/test/test_mechanize.rb +4 -9
  23. data/test/test_mechanize_cookie.rb +56 -41
  24. data/test/test_mechanize_cookie_jar.rb +27 -6
  25. data/test/test_mechanize_file_response.rb +1 -1
  26. data/test/test_mechanize_form.rb +15 -11
  27. data/test/test_mechanize_form_check_box.rb +10 -0
  28. data/test/test_mechanize_form_encoding.rb +1 -1
  29. data/test/test_mechanize_form_multi_select_list.rb +5 -1
  30. data/test/test_mechanize_http_agent.rb +52 -0
  31. data/test/test_mechanize_http_content_disposition_parser.rb +8 -1
  32. data/test/test_mechanize_http_www_authenticate_parser.rb +8 -0
  33. data/test/test_mechanize_link.rb +19 -0
  34. data/test/test_mechanize_page.rb +28 -0
  35. data/test/test_mechanize_page_image.rb +1 -1
  36. data/test/test_mechanize_page_link.rb +2 -2
  37. data/test/test_mechanize_page_meta_refresh.rb +1 -1
  38. data/test/test_mechanize_parser.rb +12 -2
  39. data/test/test_mechanize_util.rb +1 -1
  40. metadata +10 -16
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: f42c3bb7351deeb2a1a68c33b118e666925ed20a
4
- data.tar.gz: 751d2ffcf39675f4668a7d069a707a3782cafcfe
3
+ metadata.gz: 7e684f2f1ceb7fca81909282b30a28c04272caef
4
+ data.tar.gz: c08ef7e0f2aefd788f9808175afb4f97bce60b3f
5
5
  SHA512:
6
- metadata.gz: c1b85a0469fbdd35bb9ce230cf5752d4cef8f9416eab11f72ca00bc25f0f3b40065a94e31ef63944ecf8ef270a3388bbbab310b190ffbf4582f0305da3d24259
7
- data.tar.gz: 4e94e81383dccbf49bec0312e1ffe0183eaf7668679f7a77d4d5b42c2ece81337797cc16b8d61fef02dfac9077aa46ece2acce0b2418204f231ef476416b8df8
6
+ metadata.gz: fed2bde694313e6ddae6d44bbbf0ac90aa6b651ab7027628125b2095b33a73dc3fdaf8481335197ab0cf9cbea7c9dfa9396f4e3c4199cdc3563f76b20728f18c
7
+ data.tar.gz: a547f0f8d1c6f8d0b7c8ff580e487b64b79fbec3cca64a514407243529248e6892f66d9af746bc6c429458750e7b5782510cb3e8180f8464f08c8c0c0c0351b9
@@ -5,27 +5,32 @@ notifications:
5
5
  - drbrain@segment7.net
6
6
  - ljjarvis@gmail.com
7
7
  - knu@idaemons.org
8
+
8
9
  sudo: false
10
+
9
11
  # bundler is missing for jruby-head in travis-ci
10
12
  # https://github.com/travis-ci/travis-ci/issues/5861
11
- before_install: gem query -i -n ^bundler$ >/dev/null || gem install bundler
12
- rvm:
13
- - 1.9.3
14
- - 2.0.0
15
- - 2.1
16
- - 2.2
17
- - 2.3.1
18
- - ruby-head
19
- - jruby-1.7.25
20
- - jruby-9.1.2.0
21
- - jruby-head
22
- - rbx-19mode
13
+ before_install:
14
+ - gem install --conservative bundler -v'1.13.7'
15
+
23
16
  script: rake test
17
+
24
18
  matrix:
25
- allow_failures:
26
- - rvm: 2.3
19
+ include:
20
+ - rvm: 1.9.3
21
+ - rvm: 2.0.0
22
+ - rvm: 2.1
23
+ - rvm: 2.2
24
+ - rvm: 2.3.3
25
+ - rvm: 2.4.0
27
26
  - rvm: ruby-head
28
- - rvm: jruby-1.7.25
29
- - rvm: jruby-9.1.2.0
27
+ - rvm: jruby-1.7.27
28
+ - rvm: jruby-9.1.14.0
29
+ - rvm: jruby-head
30
+ allow_failures:
31
+ - rvm: jruby-9.1.14.0
30
32
  - rvm: jruby-head
31
- - rvm: rbx-19mode
33
+
34
+ env:
35
+ global:
36
+ - JRUBY_OPTS="--debug"
@@ -1,5 +1,17 @@
1
1
  = Mechanize CHANGELOG
2
2
 
3
+ === 2.7.6
4
+
5
+ * New Features
6
+ * Mechanize#set_proxy accepts an HTTP URL/URI. (#513)
7
+
8
+ * Bug fix
9
+ * Fix element(s)_with(search: selector) methods not working for forms, form fields and frames. (#444)
10
+ * Improve the filename parser for the `Content-Disposition` header. (#496, #517)
11
+ * Accept `Content-Encoding: identity`. (#515)
12
+ * Mechanize::Page#title no longer picks a title in an embeded SVG/RDF element. (#503)
13
+ * Make Mechanize::Form#has_field? boolean. (#501)
14
+
3
15
  === 2.7.5
4
16
 
5
17
  * New Features
data/Gemfile CHANGED
@@ -1,3 +1,6 @@
1
1
  source 'https://rubygems.org'
2
2
 
3
+ # In order to be able to install on 1.9.3 and 2.0.0
4
+ ruby RUBY_VERSION
5
+
3
6
  gemspec
@@ -1,4 +1,4 @@
1
- = Mechanize {<img src="https://secure.travis-ci.org/sparklemotion/mechanize.svg?rvm=1.9.3" />}[http://travis-ci.org/sparklemotion/mechanize]
1
+ = Mechanize {<img src="https://secure.travis-ci.org/sparklemotion/mechanize.svg?rvm=2.3.3" />}[http://travis-ci.org/sparklemotion/mechanize]
2
2
 
3
3
  * http://docs.seattlerb.org/mechanize
4
4
  * https://github.com/sparklemotion/mechanize
@@ -15,6 +15,9 @@ module Mechanize::ElementMatcher
15
15
  h[:dom_class] = v
16
16
  when :search, :xpath, :css
17
17
  if v
18
+ if method
19
+ warn "multiple search selectors are given; previous selector (\#{method}: \#{selector.inspect}) is ignored."
20
+ end
18
21
  selector = v
19
22
  method = k
20
23
  end
@@ -26,7 +29,7 @@ module Mechanize::ElementMatcher
26
29
 
27
30
  f = select_#{plural}(selector, method).find_all do |thing|
28
31
  criteria.all? do |k,v|
29
- v === thing.send(k)
32
+ v === thing.__send__(k)
30
33
  end
31
34
  end
32
35
  yield f if block_given?
@@ -16,7 +16,7 @@ require 'mechanize/element_matcher'
16
16
  # puts form['name']
17
17
 
18
18
  class Mechanize::Form
19
-
19
+ extend Forwardable
20
20
  extend Mechanize::ElementMatcher
21
21
 
22
22
  attr_accessor :method, :action, :name
@@ -35,12 +35,13 @@ class Mechanize::Form
35
35
 
36
36
  alias :elements :fields
37
37
 
38
- attr_reader :form_node
38
+ attr_reader :node
39
+ alias form_node node # for backward compatibility
39
40
  attr_reader :page
40
41
 
41
42
  def initialize(node, mech = nil, page = nil)
42
43
  @enctype = node['enctype'] || 'application/x-www-form-urlencoded'
43
- @form_node = node
44
+ @node = node
44
45
  @action = Mechanize::Util.html_unescape(node['action'])
45
46
  @method = (node['method'] || 'GET').upcase
46
47
  @name = node['name']
@@ -55,14 +56,14 @@ class Mechanize::Form
55
56
 
56
57
  # Returns whether or not the form contains a field with +field_name+
57
58
  def has_field?(field_name)
58
- fields.find { |f| f.name == field_name }
59
+ fields.any? { |f| f.name == field_name }
59
60
  end
60
61
 
61
62
  alias :has_key? :has_field?
62
63
 
63
64
  # Returns whether or not the form contains a field with +value+
64
65
  def has_value?(value)
65
- fields.find { |f| f.value == value }
66
+ fields.any? { |f| f.value == value }
66
67
  end
67
68
 
68
69
  # Returns all field names (keys) for this form
@@ -136,7 +137,7 @@ class Mechanize::Form
136
137
  # Note that you can also use +:id+ to get to this method:
137
138
  # page.form_with(:id => "foorm")
138
139
  def dom_id
139
- form_node['id']
140
+ @node['id']
140
141
  end
141
142
 
142
143
  # This method is a shortcut to get form's DOM class.
@@ -144,10 +145,57 @@ class Mechanize::Form
144
145
  # page.form_with(:dom_class => "foorm")
145
146
  # Note that you can also use +:class+ to get to this method:
146
147
  # page.form_with(:class => "foorm")
148
+ # However, attribute values are compared literally as string, so
149
+ # form_with(class: "a") does not match a form with class="a b".
150
+ # Use form_with(css: "form.a") instead.
147
151
  def dom_class
148
- form_node['class']
152
+ @node['class']
149
153
  end
150
154
 
155
+ ##
156
+ # :method: search
157
+ #
158
+ # Shorthand for +node.search+.
159
+ #
160
+ # See Nokogiri::XML::Node#search for details.
161
+
162
+ ##
163
+ # :method: css
164
+ #
165
+ # Shorthand for +node.css+.
166
+ #
167
+ # See also Nokogiri::XML::Node#css for details.
168
+
169
+ ##
170
+ # :method: xpath
171
+ #
172
+ # Shorthand for +node.xpath+.
173
+ #
174
+ # See also Nokogiri::XML::Node#xpath for details.
175
+
176
+ ##
177
+ # :method: at
178
+ #
179
+ # Shorthand for +node.at+.
180
+ #
181
+ # See also Nokogiri::XML::Node#at for details.
182
+
183
+ ##
184
+ # :method: at_css
185
+ #
186
+ # Shorthand for +node.at_css+.
187
+ #
188
+ # See also Nokogiri::XML::Node#at_css for details.
189
+
190
+ ##
191
+ # :method: at_xpath
192
+ #
193
+ # Shorthand for +node.at_xpath+.
194
+ #
195
+ # See also Nokogiri::XML::Node#at_xpath for details.
196
+
197
+ def_delegators :node, :search, :css, :xpath, :at, :at_css, :at_xpath
198
+
151
199
  # Add a field with +field_name+ and +value+
152
200
  def add_field!(field_name, value = nil)
153
201
  fields << Field.new({'name' => field_name}, value)
@@ -207,7 +255,7 @@ class Mechanize::Form
207
255
 
208
256
  # Treat form fields like accessors.
209
257
  def method_missing(meth, *args)
210
- method = meth.to_s.gsub(/=$/, '')
258
+ (method = meth.to_s).chomp!('=')
211
259
 
212
260
  if field(method)
213
261
  return field(method).value if args.empty?
@@ -319,7 +367,7 @@ class Mechanize::Form
319
367
  # This method adds a button to the query. If the form needs to be
320
368
  # submitted with multiple buttons, pass each button to this method.
321
369
  def add_button_to_query(button)
322
- unless button.node.document == @form_node.document then
370
+ unless button.node.document == @node.document then
323
371
  message =
324
372
  "#{button.inspect} does not belong to the same page as " \
325
373
  "the form #{@name.inspect} in #{@page.uri}"
@@ -535,7 +583,7 @@ class Mechanize::Form
535
583
  @checkboxes = []
536
584
 
537
585
  # Find all input tags
538
- form_node.search('input').each do |node|
586
+ @node.search('input').each do |node|
539
587
  type = (node['type'] || 'text').downcase
540
588
  name = node['name']
541
589
  next if name.nil? && !%w[submit button image].include?(type)
@@ -566,13 +614,13 @@ class Mechanize::Form
566
614
  end
567
615
 
568
616
  # Find all textarea tags
569
- form_node.search('textarea').each do |node|
617
+ @node.search('textarea').each do |node|
570
618
  next unless node['name']
571
619
  @fields << Textarea.new(node, node.inner_text)
572
620
  end
573
621
 
574
622
  # Find all select tags
575
- form_node.search('select').each do |node|
623
+ @node.search('select').each do |node|
576
624
  next unless node['name']
577
625
  if node.has_attribute? 'multiple'
578
626
  @fields << MultiSelectList.new(node)
@@ -583,14 +631,14 @@ class Mechanize::Form
583
631
 
584
632
  # Find all submit button tags
585
633
  # FIXME: what can I do with the reset buttons?
586
- form_node.search('button').each do |node|
634
+ @node.search('button').each do |node|
587
635
  type = (node['type'] || 'submit').downcase
588
636
  next if type == 'reset'
589
637
  @buttons << Button.new(node)
590
638
  end
591
639
 
592
640
  # Find all keygen tags
593
- form_node.search('keygen').each do |node|
641
+ @node.search('keygen').each do |node|
594
642
  @fields << Keygen.new(node, node['value'] || '')
595
643
  end
596
644
  end
@@ -14,6 +14,8 @@
14
14
  # field.value = "foo"
15
15
 
16
16
  class Mechanize::Form::Field
17
+ extend Forwardable
18
+
17
19
  attr_accessor :name, :value, :node, :type
18
20
 
19
21
  # This fields value before it's sent through Util.html_unescape.
@@ -67,6 +69,50 @@ class Mechanize::Form::Field
67
69
  node['class']
68
70
  end
69
71
 
72
+ ##
73
+ # :method: search
74
+ #
75
+ # Shorthand for +node.search+.
76
+ #
77
+ # See Nokogiri::XML::Node#search for details.
78
+
79
+ ##
80
+ # :method: css
81
+ #
82
+ # Shorthand for +node.css+.
83
+ #
84
+ # See also Nokogiri::XML::Node#css for details.
85
+
86
+ ##
87
+ # :method: xpath
88
+ #
89
+ # Shorthand for +node.xpath+.
90
+ #
91
+ # See also Nokogiri::XML::Node#xpath for details.
92
+
93
+ ##
94
+ # :method: at
95
+ #
96
+ # Shorthand for +node.at+.
97
+ #
98
+ # See also Nokogiri::XML::Node#at for details.
99
+
100
+ ##
101
+ # :method: at_css
102
+ #
103
+ # Shorthand for +node.at_css+.
104
+ #
105
+ # See also Nokogiri::XML::Node#at_css for details.
106
+
107
+ ##
108
+ # :method: at_xpath
109
+ #
110
+ # Shorthand for +node.at_xpath+.
111
+ #
112
+ # See also Nokogiri::XML::Node#at_xpath for details.
113
+
114
+ def_delegators :node, :search, :css, :xpath, :at, :at_css, :at_xpath
115
+
70
116
  def inspect # :nodoc:
71
117
  "[%s:0x%x type: %s name: %s value: %s]" % [
72
118
  self.class.name.sub(/Mechanize::Form::/, '').downcase,
@@ -12,19 +12,15 @@
12
12
  # list.value = 'one'
13
13
 
14
14
  class Mechanize::Form::MultiSelectList < Mechanize::Form::Field
15
-
16
15
  extend Mechanize::ElementMatcher
17
16
 
18
17
  attr_accessor :options
19
18
 
20
19
  def initialize node
21
20
  value = []
22
- @options = []
23
-
24
- # parse
25
- node.search('option').each do |n|
26
- @options << Mechanize::Form::Option.new(n, self)
27
- end
21
+ @options = node.search('option').map { |n|
22
+ Mechanize::Form::Option.new(n, self)
23
+ }
28
24
 
29
25
  super node, value
30
26
  end
@@ -8,12 +8,13 @@
8
8
  # select_list.first.tick
9
9
 
10
10
  class Mechanize::Form::Option
11
- attr_reader :value, :selected, :text, :select_list
11
+ attr_reader :value, :selected, :text, :select_list, :node
12
12
 
13
13
  alias :to_s :value
14
14
  alias :selected? :selected
15
15
 
16
16
  def initialize(node, select_list)
17
+ @node = node
17
18
  @text = node.inner_text
18
19
  @value = Mechanize::Util.html_unescape(node['value'] || node.inner_text)
19
20
  @selected = node.has_attribute? 'selected'
@@ -183,7 +183,13 @@ class Mechanize::HTTP::Agent
183
183
  @scheme_handlers['relative'] = @scheme_handlers['http']
184
184
  @scheme_handlers['file'] = @scheme_handlers['http']
185
185
 
186
- @http = Net::HTTP::Persistent.new connection_name
186
+ @http =
187
+ if defined?(Net::HTTP::Persistent::DEFAULT_POOL_SIZE)
188
+ Net::HTTP::Persistent.new(name: connection_name)
189
+ else
190
+ # net-http-persistent < 3.0
191
+ Net::HTTP::Persistent.new(connection_name)
192
+ end
187
193
  @http.idle_timeout = 5
188
194
  @http.keep_alive = 300
189
195
  end
@@ -530,8 +536,8 @@ class Mechanize::HTTP::Agent
530
536
 
531
537
  def request_auth request, uri
532
538
  base_uri = uri + '/'
533
- base_uri.user = nil
534
- base_uri.password = nil
539
+ base_uri.user &&= nil
540
+ base_uri.password &&= nil
535
541
  schemes = @authenticate_methods[base_uri]
536
542
 
537
543
  if realm = schemes[:digest].find { |r| r.uri == base_uri } then
@@ -644,14 +650,6 @@ class Mechanize::HTTP::Agent
644
650
  scheme = uri.relative? ? 'relative' : uri.scheme.downcase
645
651
  uri = @scheme_handlers[scheme].call(uri, referer)
646
652
 
647
- if referer_uri
648
- if uri.path.length == 0 && uri.relative?
649
- uri.path = referer_uri.path
650
- end
651
- end
652
-
653
- uri.path = '/' if uri.path.length == 0
654
-
655
653
  if uri.relative?
656
654
  raise ArgumentError, "absolute URL needed (not #{uri})" unless
657
655
  referer_uri
@@ -681,6 +679,13 @@ class Mechanize::HTTP::Agent
681
679
  raise ArgumentError, "unsupported scheme: #{uri.scheme}"
682
680
  end
683
681
 
682
+ case uri.path
683
+ when nil
684
+ raise ArgumentError, "hierarchical URL needed (not #{uri})"
685
+ when ''.freeze
686
+ uri.path = '/'
687
+ end
688
+
684
689
  uri
685
690
  end
686
691
 
@@ -817,7 +822,7 @@ class Mechanize::HTTP::Agent
817
822
  return body_io if length.zero?
818
823
 
819
824
  out_io = case response['Content-Encoding']
820
- when nil, 'none', '7bit', "" then
825
+ when nil, 'none', '7bit', 'identity', "" then
821
826
  body_io
822
827
  when 'deflate' then
823
828
  content_encoding_inflate body_io
@@ -1212,31 +1217,39 @@ class Mechanize::HTTP::Agent
1212
1217
  end
1213
1218
 
1214
1219
  ##
1215
- # Sets the proxy address, port, user, and password +addr+ should be a host,
1216
- # with no "http://", +port+ may be a port number, service name or port
1217
- # number string.
1218
-
1219
- def set_proxy addr, port, user = nil, pass = nil
1220
- unless addr and port then
1220
+ # Sets the proxy address, port, user, and password. +addr+ may be
1221
+ # an HTTP URL/URI or a host name, +port+ may be a port number, service
1222
+ # name or port number string.
1223
+
1224
+ def set_proxy addr, port = nil, user = nil, pass = nil
1225
+ case addr
1226
+ when URI::HTTP
1227
+ proxy_uri = addr.dup
1228
+ when %r{\Ahttps?://}i
1229
+ proxy_uri = URI addr
1230
+ when String
1231
+ proxy_uri = URI "http://#{addr}"
1232
+ when nil
1221
1233
  @http.proxy = nil
1222
-
1223
1234
  return
1224
1235
  end
1225
1236
 
1226
- unless Integer === port then
1237
+ case port
1238
+ when Integer
1239
+ proxy_uri.port = port
1240
+ when nil
1241
+ else
1227
1242
  begin
1228
- port = Socket.getservbyname port
1243
+ proxy_uri.port = Socket.getservbyname port
1229
1244
  rescue SocketError
1230
1245
  begin
1231
- port = Integer port
1246
+ proxy_uri.port = Integer port
1232
1247
  rescue ArgumentError
1233
1248
  raise ArgumentError, "invalid value for port: #{port.inspect}"
1234
1249
  end
1235
1250
  end
1236
1251
  end
1237
1252
 
1238
- proxy_uri = URI "http://#{addr}"
1239
- proxy_uri.port = port
1240
1253
  proxy_uri.user = user if user
1241
1254
  proxy_uri.password = pass if pass
1242
1255