capybara 3.9.0 → 3.10.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (51) hide show
  1. checksums.yaml +4 -4
  2. data/History.md +15 -0
  3. data/License.txt +1 -1
  4. data/README.md +1 -1
  5. data/lib/capybara.rb +1 -2
  6. data/lib/capybara/helpers.rb +3 -2
  7. data/lib/capybara/minitest.rb +1 -1
  8. data/lib/capybara/minitest/spec.rb +1 -0
  9. data/lib/capybara/node/finders.rb +20 -15
  10. data/lib/capybara/node/matchers.rb +43 -10
  11. data/lib/capybara/queries/current_path_query.rb +2 -2
  12. data/lib/capybara/queries/selector_query.rb +9 -2
  13. data/lib/capybara/rack_test/browser.rb +14 -13
  14. data/lib/capybara/rack_test/form.rb +32 -27
  15. data/lib/capybara/result.rb +8 -11
  16. data/lib/capybara/rspec/compound.rb +16 -26
  17. data/lib/capybara/rspec/matcher_proxies.rb +28 -11
  18. data/lib/capybara/rspec/matchers.rb +67 -45
  19. data/lib/capybara/selector.rb +22 -25
  20. data/lib/capybara/selector/builders/css_builder.rb +3 -4
  21. data/lib/capybara/selector/builders/xpath_builder.rb +4 -6
  22. data/lib/capybara/selector/regexp_disassembler.rb +43 -44
  23. data/lib/capybara/selector/selector.rb +16 -11
  24. data/lib/capybara/selenium/driver.rb +28 -21
  25. data/lib/capybara/selenium/nodes/marionette_node.rb +6 -12
  26. data/lib/capybara/server.rb +1 -3
  27. data/lib/capybara/server/animation_disabler.rb +2 -2
  28. data/lib/capybara/session.rb +1 -1
  29. data/lib/capybara/spec/session/assert_all_of_selectors_spec.rb +29 -0
  30. data/lib/capybara/spec/session/click_button_spec.rb +6 -0
  31. data/lib/capybara/spec/session/click_link_spec.rb +1 -1
  32. data/lib/capybara/spec/session/has_all_selectors_spec.rb +1 -1
  33. data/lib/capybara/spec/session/has_any_selectors_spec.rb +25 -0
  34. data/lib/capybara/spec/session/html_spec.rb +7 -0
  35. data/lib/capybara/spec/session/node_spec.rb +5 -1
  36. data/lib/capybara/spec/session/refresh_spec.rb +4 -0
  37. data/lib/capybara/spec/session/window/switch_to_window_spec.rb +4 -0
  38. data/lib/capybara/spec/session/window/window_opened_by_spec.rb +4 -0
  39. data/lib/capybara/spec/session/window/window_spec.rb +4 -0
  40. data/lib/capybara/spec/session/window/windows_spec.rb +4 -0
  41. data/lib/capybara/spec/views/form.erb +2 -2
  42. data/lib/capybara/version.rb +1 -1
  43. data/spec/minitest_spec.rb +5 -1
  44. data/spec/minitest_spec_spec.rb +5 -1
  45. data/spec/regexp_dissassembler_spec.rb +5 -3
  46. data/spec/rspec_spec.rb +20 -0
  47. data/spec/selector_spec.rb +89 -3
  48. data/spec/selenium_spec_chrome.rb +3 -7
  49. data/spec/selenium_spec_marionette.rb +1 -4
  50. metadata +20 -6
  51. data/lib/capybara/xpath_patches.rb +0 -27
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 42a9311d8f3e7670a90f5851cc9927db169022d550e1c9b2a086900145b7ad18
4
- data.tar.gz: 8159deadf9826514634c55f9744d2b8f18a910434d71f66870eb299f6c5980ff
3
+ metadata.gz: 58e17a63edc194f43995b9c63196fe91311450999a03da4ee7c2f1aa1e1e34e4
4
+ data.tar.gz: f0a20f11e8a454f62a9abd62dc4d1f18f8419460c43a0e37f250d8c603cffc60
5
5
  SHA512:
6
- metadata.gz: 8d8256a0c4bc0ca9586d65aec40d4814c060226a7902f5122271d4c9e22b63eec1568c81315d327e02873d732062beef6a0c01d0a50df9d49e14fcd0189084c0
7
- data.tar.gz: a86ce539c90c9fbaea0ac8165bbf6f1b66ee8fa4589c129c366d88730cb1881616a3260c3a710b546c0e833aa708de8791326cbaa9c5ffe5f8875ce249c779cd
6
+ metadata.gz: ee9b34f496afec3a99be65c5fcdcfebef38640eccb146a4e43ec811a55c99edf8393695e9a9d228db07d738d753feaa7f8c8090bc7cf37189ff3b192e5b15482
7
+ data.tar.gz: 002ae33fdef7b207d2cba11b8ce125c1d4ef972b10226d9f766dc41605791b8167c11c69ae1295ff229049bbd668a4b49021747eefee4861b152489ddbbe4f5d
data/History.md CHANGED
@@ -1,3 +1,18 @@
1
+ # Version 3.10.0
2
+ Release date: 2018-10-23
3
+
4
+ ### Added
5
+
6
+ * :class filter can now check for class names starting with !
7
+ * Selector `xpath`/`css` expression definitions will get filter names from block parameters if not explicitly provided
8
+ * `any_of_selectors` assertions and matchers to complement `all_of_selectors` and `none_of_selectors`
9
+
10
+ ### Fixed
11
+
12
+ * Selector `css` expression definiton declared filters now work again
13
+ * Cleaned up warnings [Yuji Yaginuma]
14
+ * Workaround installation of rspec matcher proxies under jruby by reverting to the old solution not using prepend, so jruby bugs are not hit - Issue #2115
15
+
1
16
  # Version 3.9.0
2
17
  Release date: 2018-10-03
3
18
 
@@ -1,6 +1,6 @@
1
1
  (The MIT License)
2
2
 
3
- Copyright (c) 2009-2016 Jonas Nicklas
3
+ Copyright (c) 2009-2018 Thomas Walpole, Jonas Nicklas
4
4
 
5
5
  Permission is hereby granted, free of charge, to any person obtaining
6
6
  a copy of this software and associated documentation files (the
data/README.md CHANGED
@@ -7,7 +7,7 @@
7
7
  [![SemVer](https://api.dependabot.com/badges/compatibility_score?dependency-name=capybara&package-manager=bundler&version-scheme=semver)](https://dependabot.com/compatibility-score.html?dependency-name=capybara&package-manager=bundler&version-scheme=semver)
8
8
 
9
9
  **Note** You are viewing the README for the development version of Capybara. If you are using the current release version
10
- you can find the README at https://github.com/teamcapybara/capybara/blob/3.8_stable/README.md
10
+ you can find the README at https://github.com/teamcapybara/capybara/blob/3.9_stable/README.md
11
11
 
12
12
 
13
13
  Capybara helps you test web applications by simulating how a real user would
@@ -393,7 +393,7 @@ module Capybara
393
393
  if threadsafe
394
394
  Thread.current['capybara_specified_session']
395
395
  else
396
- @specified_session
396
+ @specified_session ||= nil
397
397
  end
398
398
  end
399
399
 
@@ -414,7 +414,6 @@ module Capybara
414
414
  module RackTest; end
415
415
  module Selenium; end
416
416
 
417
- require 'capybara/xpath_patches'
418
417
  require 'capybara/helpers'
419
418
  require 'capybara/session'
420
419
  require 'capybara/window'
@@ -49,8 +49,9 @@ module Capybara
49
49
  #
50
50
  def inject_asset_host(html, host: Capybara.asset_host)
51
51
  if host && Nokogiri::HTML(html).css('base').empty?
52
- match = html.match(/<head[^<]*?>/)
53
- return html.clone.insert match.end(0), "<base href='#{host}' />" if match
52
+ html.match(/<head[^<]*?>/) do |m|
53
+ return html.clone.insert m.end(0), "<base href='#{host}' />"
54
+ end
54
55
  end
55
56
  html
56
57
  end
@@ -87,7 +87,7 @@ module Capybara
87
87
  # see {Capybara::Node::Matchers#assert_style}
88
88
 
89
89
  %w[assert_selector assert_no_selector
90
- assert_all_of_selectors assert_none_of_selectors
90
+ assert_all_of_selectors assert_none_of_selectors assert_any_of_selectors
91
91
  assert_matches_selector assert_not_matches_selector
92
92
  assert_style].each do |assertion_name|
93
93
  class_eval <<-ASSERTION, __FILE__, __LINE__ + 1
@@ -16,6 +16,7 @@ module Capybara
16
16
  %W[refute_#{assertion} wont_have_#{assertion}]]
17
17
  end + [%w[assert_all_of_selectors must_have_all_of_selectors],
18
18
  %w[assert_none_of_selectors must_have_none_of_selectors],
19
+ %w[assert_any_of_selectors must_have_any_of_selectors],
19
20
  %w[assert_style must_have_style]] +
20
21
  %w[selector xpath css].flat_map do |assertion|
21
22
  [%W[assert_matches_#{assertion} must_match_#{assertion}],
@@ -15,15 +15,30 @@ module Capybara
15
15
  # and defaults to 2 seconds.
16
16
  # @option options [false, Numeric] wait (Capybara.default_max_wait_time) Maximum time to wait for matching element to appear.
17
17
  #
18
- # +find+ takes the same options as +all+.
19
- #
20
18
  # page.find('#foo').find('.bar')
21
19
  # page.find(:xpath, './/div[contains(., "bar")]')
22
20
  # page.find('li', text: 'Quox').click_link('Delete')
23
21
  #
24
22
  # @param (see Capybara::Node::Finders#all)
25
23
  #
26
- # @option options [Boolean] match The matching strategy to use.
24
+ # @!macro system_filters
25
+ # @option options [String, Regexp] text Only find elements which contain this text or match this regexp
26
+ # @option options [String, Boolean] exact_text (Capybara.exact_text) When String the elements contained text must match exactly, when Boolean controls whether the :text option must match exactly
27
+ # @option options [Boolean] normalize_ws (Capybara.default_normalize_ws) Whether the `text`/`exact_text` options are compared against elment text with whitespace normalized or as returned by the driver
28
+ # @option options [Boolean, Symbol] visible Only find elements with the specified visibility:
29
+ # * true - only finds visible elements.
30
+ # * false - finds invisible _and_ visible elements.
31
+ # * :all - same as false; finds visible and invisible elements.
32
+ # * :hidden - only finds invisible elements.
33
+ # * :visible - same as true; only finds visible elements.
34
+ # @option options [String, Regexp] id Only find elements with an id that matches the value passed
35
+ # @option options [String, Array<String>, Regexp] class Only find elements with matching class/classes.
36
+ # + Absence of a class can be checked by prefixing the class name with !
37
+ # + If you need to check for existence of a class name that starts with ! then prefix with !!
38
+ # + ```class:['a', '!b', '!!!c'] # limit to elements with class 'a' and '!c' but not class 'b'```
39
+ # @option options [Boolean] exact Control whether `is` expressions in the given XPath match exactly or partially
40
+ # @option options [Integer, false] wait (Capybara.default_max_wait_time) The time to wait for matching elements to become available
41
+ # @option options [Symbol] match The matching strategy to use.
27
42
  #
28
43
  # @return [Capybara::Node::Element] The found element
29
44
  # @raise [Capybara::ElementNotFound] If the element can't be found before time expires
@@ -46,7 +61,7 @@ module Capybara
46
61
  #
47
62
  # @param (see Capybara::Node::Finders#find)
48
63
  #
49
- # @!macro waiting_behavior
64
+ # @macro waiting_behavior
50
65
  #
51
66
  # @option options [Boolean] match The matching strategy to use.
52
67
  #
@@ -221,21 +236,11 @@ module Capybara
221
236
  #
222
237
  # @param [Symbol] kind Optional selector type (:css, :xpath, :field, etc.) - Defaults to Capybara.default_selector
223
238
  # @param [String] locator The locator for the specified selector
224
- # @option options [String, Regexp] text Only find elements which contain this text or match this regexp
225
- # @option options [String, Boolean] exact_text (Capybara.exact_text) When String the elements contained text must match exactly, when Boolean controls whether the :text option must match exactly
226
- # @option options [Boolean] normalize_ws (Capybara.default_normalize_ws) Whether the `text`/`exact_text` options are compared against elment text with whitespace normalized or as returned by the driver
227
- # @option options [Boolean, Symbol] visible Only find elements with the specified visibility:
228
- # * true - only finds visible elements.
229
- # * false - finds invisible _and_ visible elements.
230
- # * :all - same as false; finds visible and invisible elements.
231
- # * :hidden - only finds invisible elements.
232
- # * :visible - same as true; only finds visible elements.
239
+ # @macro system_filters
233
240
  # @option options [Integer] count Exact number of matches that are expected to be found
234
241
  # @option options [Integer] maximum Maximum number of matches that are expected to be found
235
242
  # @option options [Integer] minimum Minimum number of matches that are expected to be found
236
243
  # @option options [Range] between Number of matches found must be within the given range
237
- # @option options [Boolean] exact Control whether `is` expressions in the given XPath match exactly or partially
238
- # @option options [Integer, false] wait (Capybara.default_max_wait_time) The time to wait for matching elements to become available
239
244
  # @overload all([kind = Capybara.default_selector], locator = nil, **options)
240
245
  # @overload all([kind = Capybara.default_selector], locator = nil, **options, &filter_block)
241
246
  # @yieldparam element [Capybara::Node::Element] The element being considered for inclusion in the results
@@ -139,13 +139,9 @@ module Capybara
139
139
  #
140
140
  # @overload assert_all_of_selectors([kind = Capybara.default_selector], *locators, **options)
141
141
  #
142
- def assert_all_of_selectors(*args, wait: nil, **options, &optional_filter_block)
143
- wait = session_options.default_max_wait_time if wait.nil?
144
- selector = extract_selector(args)
145
- synchronize(wait) do
146
- args.each do |locator|
147
- assert_selector(selector, locator, options, &optional_filter_block)
148
- end
142
+ def assert_all_of_selectors(*args, **options, &optional_filter_block)
143
+ _verify_multiple(*args, options) do |selector, locator, opts|
144
+ assert_selector(selector, locator, opts, &optional_filter_block)
149
145
  end
150
146
  end
151
147
 
@@ -164,13 +160,42 @@ module Capybara
164
160
  #
165
161
  # @overload assert_none_of_selectors([kind = Capybara.default_selector], *locators, **options)
166
162
  #
167
- def assert_none_of_selectors(*args, wait: nil, **options, &optional_filter_block)
163
+ def assert_none_of_selectors(*args, **options, &optional_filter_block)
164
+ _verify_multiple(*args, options) do |selector, locator, opts|
165
+ assert_no_selector(selector, locator, opts, &optional_filter_block)
166
+ end
167
+ end
168
+
169
+ # Asserts that any of the provided selectors are present on the given page
170
+ # or descendants of the current node. If options are provided, the assertion
171
+ # will check that each locator is present with those options as well (other than :wait).
172
+ #
173
+ # page.assert_any_of_selectors(:custom, 'Tom', 'Joe', visible: all)
174
+ # page.assert_any_of_selectors(:css, '#my_div', 'a.not_clicked')
175
+ #
176
+ # It accepts all options that {Capybara::Node::Finders#all} accepts,
177
+ # such as :text and :visible.
178
+ #
179
+ # The :wait option applies to all of the selectors as a group, so any of the locators must be present
180
+ # within :wait (Defaults to Capybara.default_max_wait_time) seconds.
181
+ #
182
+ # @overload assert_any_of_selectors([kind = Capybara.default_selector], *locators, **options)
183
+ #
184
+ def assert_any_of_selectors(*args, wait: nil, **options, &optional_filter_block)
168
185
  wait = session_options.default_max_wait_time if wait.nil?
169
186
  selector = extract_selector(args)
170
187
  synchronize(wait) do
171
- args.each do |locator|
172
- assert_no_selector(selector, locator, options, &optional_filter_block)
188
+ res = args.map do |locator|
189
+ begin
190
+ assert_selector(selector, locator, options, &optional_filter_block)
191
+ break nil
192
+ rescue Capybara::ExpectationNotMet => e
193
+ e.message
194
+ end
173
195
  end
196
+ raise Capybara::ExpectationNotMet, res.join(' or ') if res
197
+
198
+ true
174
199
  end
175
200
  end
176
201
 
@@ -700,6 +725,14 @@ module Capybara
700
725
  args.first.is_a?(Symbol) ? args.shift : session_options.default_selector
701
726
  end
702
727
 
728
+ def _verify_multiple(*args, wait: nil, **options)
729
+ wait = session_options.default_max_wait_time if wait.nil?
730
+ selector = extract_selector(args)
731
+ synchronize(wait) do
732
+ args.each { |locator| yield(selector, locator, options) }
733
+ end
734
+ end
735
+
703
736
  def _verify_selector_result(query_args, optional_filter_block)
704
737
  query_args = _set_query_session_options(*query_args)
705
738
  query = Capybara::Queries::SelectorQuery.new(*query_args, &optional_filter_block)
@@ -18,8 +18,8 @@ module Capybara
18
18
 
19
19
  def resolves_for?(session)
20
20
  uri = ::Addressable::URI.parse(session.current_url)
21
- uri.query = nil if uri && options[:ignore_query]
22
- @actual_path = options[:url] ? uri.to_s : uri&.request_uri
21
+ uri&.query = nil if options[:ignore_query]
22
+ @actual_path = options[:url] ? uri&.to_s : uri&.request_uri
23
23
 
24
24
  if @expected_path.is_a? Regexp
25
25
  @actual_path.to_s.match(@expected_path)
@@ -61,8 +61,7 @@ module Capybara
61
61
  return true if (@resolved_node&.== node) && options[:allow_self]
62
62
 
63
63
  @applied_filters ||= :system
64
- return false unless matches_id_filter?(node) && matches_class_filter?(node)
65
- return false unless matches_text_filter?(node) && matches_exact_text_filter?(node) && matches_visible_filter?(node)
64
+ return false unless matches_system_filters?(node)
66
65
 
67
66
  @applied_filters = :node
68
67
  matches_node_filters?(node) && matches_filter_block?(node)
@@ -292,6 +291,14 @@ module Capybara
292
291
  node.is_a?(::Capybara::Node::Simple) && node.path == '/'
293
292
  end
294
293
 
294
+ def matches_system_filters?(node)
295
+ matches_id_filter?(node) &&
296
+ matches_class_filter?(node) &&
297
+ matches_text_filter?(node) &&
298
+ matches_exact_text_filter?(node) &&
299
+ matches_visible_filter?(node)
300
+ end
301
+
295
302
  def matches_id_filter?(node)
296
303
  return true unless use_default_id_filter? && options[:id].is_a?(Regexp)
297
304
 
@@ -57,25 +57,26 @@ class Capybara::RackTest::Browser
57
57
  end
58
58
 
59
59
  def process(method, path, attributes = {}, env = {})
60
- new_uri = URI.parse(path)
61
- method.downcase! unless method.is_a? Symbol
62
- if path.empty?
63
- new_uri.path = request_path
64
- else
65
- new_uri.path = request_path if path.start_with?('?')
66
- new_uri.path = '/' if new_uri.path.empty?
67
- new_uri.path = request_path.sub(%r{/[^/]*$}, '/') + new_uri.path unless new_uri.path.start_with?('/')
68
- end
69
- new_uri.scheme ||= @current_scheme
70
- new_uri.host ||= @current_host
71
- new_uri.port ||= @current_port unless new_uri.default_port == @current_port
72
-
60
+ method = method.downcase
61
+ new_uri = build_uri(path)
73
62
  @current_scheme, @current_host, @current_port = new_uri.select(:scheme, :host, :port)
74
63
 
75
64
  reset_cache!
76
65
  send(method, new_uri.to_s, attributes, env.merge(options[:headers] || {}))
77
66
  end
78
67
 
68
+ def build_uri(path)
69
+ URI.parse(path).tap do |uri|
70
+ uri.path = request_path if path.empty? || path.start_with?('?')
71
+ uri.path = '/' if uri.path.empty?
72
+ uri.path = request_path.sub(%r{/[^/]*$}, '/') + uri.path unless uri.path.start_with?('/')
73
+
74
+ uri.scheme ||= @current_scheme
75
+ uri.host ||= @current_host
76
+ uri.port ||= @current_port unless uri.default_port == @current_port
77
+ end
78
+ end
79
+
79
80
  def current_url
80
81
  last_request.url
81
82
  rescue Rack::Test::Error
@@ -19,25 +19,22 @@ class Capybara::RackTest::Form < Capybara::RackTest::Node
19
19
  end
20
20
 
21
21
  def params(button)
22
- params = make_params
23
-
24
- form_element_types = %i[input select textarea]
22
+ form_element_types = %i[input select textarea button]
25
23
  form_elements_xpath = XPath.generate do |xp|
26
24
  xpath = xp.descendant(*form_element_types).where(!xp.attr(:form))
27
25
  xpath += xp.anywhere(*form_element_types).where(xp.attr(:form) == native[:id]) if native[:id]
28
26
  xpath.where(!xp.attr(:disabled))
29
27
  end.to_s
30
28
 
31
- native.xpath(form_elements_xpath).map do |field|
29
+ form_elements = native.xpath(form_elements_xpath).reject { |el| submitter?(el) && (el != button.native) }
30
+
31
+ form_elements.each_with_object(make_params) do |field, params|
32
32
  case field.name
33
- when 'input' then add_input_param(field, params)
33
+ when 'input', 'button' then add_input_param(field, params)
34
34
  when 'select' then add_select_param(field, params)
35
35
  when 'textarea' then add_textarea_param(field, params)
36
36
  end
37
- end
38
- merge_param!(params, button[:name], button[:value] || '') if button[:name]
39
-
40
- params.to_params_hash
37
+ end.to_params_hash
41
38
  end
42
39
 
43
40
  def submit(button)
@@ -80,28 +77,32 @@ private
80
77
  end
81
78
 
82
79
  def add_input_param(field, params)
83
- if %w[radio checkbox].include? field['type']
84
- if field['checked']
85
- node = Capybara::RackTest::Node.new(driver, field)
86
- merge_param!(params, field['name'], node.value.to_s)
87
- end
88
- elsif %w[submit image].include? field['type']
89
- # TODO: identify the click button here (in document order, rather
90
- # than leaving until the end of the params)
91
- elsif field['type'] == 'file'
80
+ name, value = field['name'].to_s, field['value'].to_s
81
+ return if name.empty?
82
+
83
+ value = case field['type']
84
+ when 'radio', 'checkbox'
85
+ return unless field['checked']
86
+
87
+ Capybara::RackTest::Node.new(driver, field).value.to_s
88
+ when 'file'
92
89
  if multipart?
93
- file = if (value = field['value']).to_s.empty?
94
- NilUploadedFile.new
95
- else
96
- mime_info = MiniMime.lookup_by_filename(value)
97
- Rack::Test::UploadedFile.new(value, mime_info&.content_type&.to_s)
98
- end
99
- merge_param!(params, field['name'], file)
90
+ file_to_upload(value)
100
91
  else
101
- merge_param!(params, field['name'], File.basename(field['value'].to_s))
92
+ File.basename(value)
102
93
  end
103
94
  else
104
- merge_param!(params, field['name'], field['value'].to_s)
95
+ value
96
+ end
97
+ merge_param!(params, name, value)
98
+ end
99
+
100
+ def file_to_upload(filename)
101
+ if filename.empty?
102
+ NilUploadedFile.new
103
+ else
104
+ mime_info = MiniMime.lookup_by_filename(filename)
105
+ Rack::Test::UploadedFile.new(filename, mime_info&.content_type&.to_s)
105
106
  end
106
107
  end
107
108
 
@@ -119,4 +120,8 @@ private
119
120
  def add_textarea_param(field, params)
120
121
  merge_param!(params, field['name'], field['_capybara_raw_value'].to_s.gsub(/\n/, "\r\n"))
121
122
  end
123
+
124
+ def submitter?(el)
125
+ (%w[submit image].include? el['type']) || (el.name == 'button')
126
+ end
122
127
  end
@@ -32,7 +32,7 @@ module Capybara
32
32
 
33
33
  def_delegators :full_results, :size, :length, :last, :values_at, :inspect, :sample
34
34
 
35
- alias :index :find_index
35
+ alias index find_index
36
36
 
37
37
  def each(&block)
38
38
  return enum_for(:each) unless block_given?
@@ -73,28 +73,25 @@ module Capybara
73
73
  end
74
74
 
75
75
  def compare_count
76
+ count, min, max, between = @query.options.values_at(:count, :minimum, :maximum, :between)
77
+
76
78
  # Only check filters for as many elements as necessary to determine result
77
- if (count = @query.options[:count])
78
- count = Integer(count)
79
+ if count && (count = Integer(count))
79
80
  return load_up_to(count + 1) <=> count
80
81
  end
81
82
 
82
- if (min = @query.options[:minimum])
83
- min = Integer(min)
83
+ if min && (min = Integer(min))
84
84
  return -1 if load_up_to(min) < min
85
85
  end
86
86
 
87
- if (max = @query.options[:maximum])
88
- max = Integer(max)
87
+ if max && (max = Integer(max))
89
88
  return 1 if load_up_to(max + 1) > max
90
89
  end
91
90
 
92
- if (between = @query.options[:between])
91
+ if between
93
92
  min, max = between.minmax
94
93
  size = load_up_to(max + 1)
95
- return 0 if between.include? size
96
-
97
- return size <=> min
94
+ return between.include?(size) ? 0 : size <=> min
98
95
  end
99
96
 
100
97
  0