Binary files /tmp/tmp82VLlK/Bsa_kABdLX/ruby-xpath-2.0.0/data.tar.gz.sig and /tmp/tmp82VLlK/NBwL5eDspx/ruby-xpath-3.2.0/data.tar.gz.sig differ diff -Nru ruby-xpath-2.0.0/debian/changelog ruby-xpath-3.2.0/debian/changelog --- ruby-xpath-2.0.0/debian/changelog 2015-09-09 10:37:57.000000000 +0000 +++ ruby-xpath-3.2.0/debian/changelog 2019-01-05 15:01:28.000000000 +0000 @@ -1,3 +1,20 @@ +ruby-xpath (3.2.0-1) unstable; urgency=medium + + [ Cédric Boutillier ] + * Use https:// in Vcs-* fields + * Bump Standards-Version to 3.9.7 (no changes needed) + * Run wrap-and-sort on packaging files + + [ Pirate Praveen ] + * New upstream version 3.2.0 + * Bump debhelper compatibility level to 11 + * Use salsa.debian.org in Vcs-* fields + * Bump Standards-Version to 4.3.0 (no changes needed) + * Move debian/watch to gemwatch.debian.net + * Add myself as an uploader + + -- Pirate Praveen Sat, 05 Jan 2019 20:31:28 +0530 + ruby-xpath (2.0.0-2) unstable; urgency=medium * Team upload. diff -Nru ruby-xpath-2.0.0/debian/compat ruby-xpath-3.2.0/debian/compat --- ruby-xpath-2.0.0/debian/compat 2015-09-09 10:37:57.000000000 +0000 +++ ruby-xpath-3.2.0/debian/compat 2019-01-05 15:01:28.000000000 +0000 @@ -1 +1 @@ -9 +11 diff -Nru ruby-xpath-2.0.0/debian/control ruby-xpath-3.2.0/debian/control --- ruby-xpath-2.0.0/debian/control 2015-09-09 10:37:57.000000000 +0000 +++ ruby-xpath-3.2.0/debian/control 2019-01-05 15:01:28.000000000 +0000 @@ -2,15 +2,16 @@ Section: ruby Priority: optional Maintainer: Debian Ruby Extras Maintainers -Uploaders: Markus Tornow -Build-Depends: debhelper (>= 9~), +Uploaders: Markus Tornow , + Pirate Praveen +Build-Depends: debhelper (>= 11~), gem2deb, rake, ruby-nokogiri (>= 1.3), ruby-rspec -Standards-Version: 3.9.6 -Vcs-Git: git://anonscm.debian.org/pkg-ruby-extras/ruby-xpath.git -Vcs-Browser: https://anonscm.debian.org/cgit/pkg-ruby-extras/ruby-xpath.git +Standards-Version: 4.3.0 +Vcs-Git: https://salsa.debian.org/ruby-team/ruby-xpath.git +Vcs-Browser: https://salsa.debian.org/ruby-team/ruby-xpath Homepage: http://github.com/jnicklas/xpath Testsuite: autopkgtest-pkg-ruby XS-Ruby-Versions: all diff -Nru ruby-xpath-2.0.0/debian/copyright ruby-xpath-3.2.0/debian/copyright --- ruby-xpath-2.0.0/debian/copyright 2015-09-09 10:37:57.000000000 +0000 +++ ruby-xpath-3.2.0/debian/copyright 2019-01-05 15:01:28.000000000 +0000 @@ -31,5 +31,3 @@ WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - - diff -Nru ruby-xpath-2.0.0/debian/watch ruby-xpath-3.2.0/debian/watch --- ruby-xpath-2.0.0/debian/watch 2015-09-09 10:37:57.000000000 +0000 +++ ruby-xpath-3.2.0/debian/watch 2019-01-05 15:01:28.000000000 +0000 @@ -1,2 +1,2 @@ version=3 -http://pkg-ruby-extras.alioth.debian.org/cgi-bin/gemwatch/xpath .*/xpath-(.*).tar.gz +https://gemwatch.debian.net/xpath .*/xpath-(.*).tar.gz diff -Nru ruby-xpath-2.0.0/lib/xpath/dsl.rb ruby-xpath-3.2.0/lib/xpath/dsl.rb --- ruby-xpath-2.0.0/lib/xpath/dsl.rb 2013-05-23 00:36:05.000000000 +0000 +++ ruby-xpath-3.2.0/lib/xpath/dsl.rb 2019-01-05 15:00:16.000000000 +0000 @@ -1,112 +1,174 @@ +# frozen_string_literal: true + module XPath module DSL - module TopLevel - def current - Expression.new(:this_node) - end + def current + Expression.new(:this_node) + end - def name - Expression.new(:node_name, current) - end + def descendant(*expressions) + Expression.new(:descendant, current, expressions) + end - def descendant(*expressions) - Expression.new(:descendant, current, expressions) - end + def child(*expressions) + Expression.new(:child, current, expressions) + end - def child(*expressions) - Expression.new(:child, current, expressions) - end + def axis(name, *element_names) + Expression.new(:axis, current, name, element_names) + end - def axis(name, tag_name=:*) - Expression.new(:axis, current, name, tag_name) - end + def anywhere(*expressions) + Expression.new(:anywhere, expressions) + end - def next_sibling(*expressions) - Expression.new(:next_sibling, current, expressions) - end + def attr(expression) + Expression.new(:attribute, current, expression) + end - def previous_sibling(*expressions) - Expression.new(:previous_sibling, current, expressions) - end + def text + Expression.new(:text, current) + end - def anywhere(*expressions) - Expression.new(:anywhere, expressions) - end + def css(selector) + Expression.new(:css, current, Literal.new(selector)) + end - def attr(expression) - Expression.new(:attribute, current, expression) - end + def function(name, *arguments) + Expression.new(:function, name, *arguments) + end - def contains(expression) - Expression.new(:contains, current, expression) - end + def method(name, *arguments) + Expression.new(:function, name, current, *arguments) + end - def starts_with(expression) - Expression.new(:starts_with, current, expression) + def where(expression) + if expression + Expression.new(:where, current, expression) + else + current end + end + alias_method :[], :where - def text - Expression.new(:text, current) - end + def is(expression) + Expression.new(:is, current, expression) + end - def string - Expression.new(:string_function, current) - end + def binary_operator(name, rhs) + Expression.new(:binary_operator, name, current, rhs) + end - def css(selector) - Expression.new(:css, current, Literal.new(selector)) - end + def union(*expressions) + Union.new(*[self, expressions].flatten) end + alias_method :+, :union - module ExpressionLevel - include XPath::DSL::TopLevel + def last + function(:last) + end - def where(expression) - Expression.new(:where, current, expression) - end - alias_method :[], :where + def position + function(:position) + end - def one_of(*expressions) - Expression.new(:one_of, current, expressions) + METHODS = [ + # node set + :count, :id, :local_name, :namespace_uri, + # string + :string, :concat, :starts_with, :contains, :substring_before, + :substring_after, :substring, :string_length, :normalize_space, + :translate, + # boolean + :boolean, :not, :true, :false, :lang, + # number + :number, :sum, :floor, :ceiling, :round + ].freeze + + METHODS.each do |key| + name = key.to_s.tr('_', '-').to_sym + define_method key do |*args| + method(name, *args) end + end - def equals(expression) - Expression.new(:equality, current, expression) - end - alias_method :==, :equals + def qname + method(:name) + end - def is(expression) - Expression.new(:is, current, expression) + alias_method :inverse, :not + alias_method :~, :not + alias_method :!, :not + alias_method :normalize, :normalize_space + alias_method :n, :normalize_space + + OPERATORS = [ + %i[equals = ==], + %i[or or |], + %i[and and &], + %i[not_equals != !=], + %i[lte <= <=], + %i[lt < <], + %i[gte >= >=], + %i[gt > >], + %i[plus +], + %i[minus -], + %i[multiply * *], + %i[divide div /], + %i[mod mod %] + ].freeze + + OPERATORS.each do |(name, operator, alias_name)| + define_method name do |rhs| + binary_operator(operator, rhs) end + alias_method alias_name, name if alias_name + end - def or(expression) - Expression.new(:or, current, expression) + AXES = %i[ + ancestor ancestor_or_self attribute descendant_or_self + following following_sibling namespace parent preceding + preceding_sibling self + ].freeze + + AXES.each do |key| + name = key.to_s.tr('_', '-').to_sym + define_method key do |*element_names| + axis(name, *element_names) end - alias_method :|, :or + end - def and(expression) - Expression.new(:and, current, expression) - end - alias_method :&, :and + alias_method :self_axis, :self - def union(*expressions) - Union.new(*[self, expressions].flatten) - end - alias_method :+, :union + def ends_with(suffix) + function(:substring, current, function(:'string-length', current).minus(function(:'string-length', suffix)).plus(1)) == suffix + end - def inverse - Expression.new(:inverse, current) - end - alias_method :~, :inverse + def contains_word(word) + function(:concat, ' ', current.normalize_space, ' ').contains(" #{word} ") + end - def string_literal - Expression.new(:string_literal, self) - end + UPPERCASE_LETTERS = 'ABCDEFGHIJKLMNOPQRSTUVWXYZÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖØÙÚÛÜÝÞŸŽŠŒ' + LOWERCASE_LETTERS = 'abcdefghijklmnopqrstuvwxyzàáâãäåæçèéêëìíîïðñòóôõöøùúûüýþÿžšœ' - def normalize - Expression.new(:normalized_space, current) - end - alias_method :n, :normalize + def lowercase + method(:translate, UPPERCASE_LETTERS, LOWERCASE_LETTERS) + end + + def uppercase + method(:translate, LOWERCASE_LETTERS, UPPERCASE_LETTERS) + end + + def one_of(*expressions) + expressions.map { |e| current.equals(e) }.reduce(:or) + end + + def next_sibling(*expressions) + axis(:"following-sibling")[1].axis(:self, *expressions) + end + + def previous_sibling(*expressions) + axis(:"preceding-sibling")[1].axis(:self, *expressions) end end end diff -Nru ruby-xpath-2.0.0/lib/xpath/expression.rb ruby-xpath-3.2.0/lib/xpath/expression.rb --- ruby-xpath-2.0.0/lib/xpath/expression.rb 2013-05-23 00:36:05.000000000 +0000 +++ ruby-xpath-3.2.0/lib/xpath/expression.rb 2019-01-05 15:00:16.000000000 +0000 @@ -1,7 +1,9 @@ +# frozen_string_literal: true + module XPath class Expression attr_accessor :expression, :arguments - include XPath::DSL::ExpressionLevel + include XPath::DSL def initialize(expression, *arguments) @expression = expression @@ -12,7 +14,7 @@ self end - def to_xpath(type=nil) + def to_xpath(type = nil) Renderer.render(self, type) end alias_method :to_s, :to_xpath diff -Nru ruby-xpath-2.0.0/lib/xpath/html.rb ruby-xpath-3.2.0/lib/xpath/html.rb --- ruby-xpath-2.0.0/lib/xpath/html.rb 2013-05-23 00:36:05.000000000 +0000 +++ ruby-xpath-3.2.0/lib/xpath/html.rb 1970-01-01 00:00:00.000000000 +0000 @@ -1,175 +0,0 @@ -module XPath - module HTML - include XPath::DSL::TopLevel - extend self - - # Match an `a` link element. - # - # @param [String] locator - # Text, id, title, or image alt attribute of the link - # - def link(locator) - locator = locator.to_s - link = descendant(:a)[attr(:href)] - link[attr(:id).equals(locator) | string.n.is(locator) | attr(:title).is(locator) | descendant(:img)[attr(:alt).is(locator)]] - end - - # Match a `submit`, `image`, or `button` element. - # - # @param [String] locator - # Value, title, id, or image alt attribute of the button - # - def button(locator) - locator = locator.to_s - button = descendant(:input)[attr(:type).one_of('submit', 'reset', 'image', 'button')][attr(:id).equals(locator) | attr(:value).is(locator) | attr(:title).is(locator)] - button += descendant(:button)[attr(:id).equals(locator) | attr(:value).is(locator) | string.n.is(locator) | attr(:title).is(locator)] - button += descendant(:input)[attr(:type).equals('image')][attr(:alt).is(locator)] - end - - - # Match anything returned by either {#link} or {#button}. - # - # @param [String] locator - # Text, id, title, or image alt attribute of the link or button - # - def link_or_button(locator) - link(locator) + button(locator) - end - - - # Match any `fieldset` element. - # - # @param [String] locator - # Legend or id of the fieldset - # - def fieldset(locator) - locator = locator.to_s - descendant(:fieldset)[attr(:id).equals(locator) | child(:legend)[string.n.is(locator)]] - end - - - # Match any `input`, `textarea`, or `select` element that doesn't have a - # type of `submit`, `image`, or `hidden`. - # - # @param [String] locator - # Label, id, or name of field to match - # - def field(locator) - locator = locator.to_s - xpath = descendant(:input, :textarea, :select)[~attr(:type).one_of('submit', 'image', 'hidden')] - xpath = locate_field(xpath, locator) - xpath - end - - - # Match any `input` or `textarea` element that can be filled with text. - # This excludes any inputs with a type of `submit`, `image`, `radio`, - # `checkbox`, `hidden`, or `file`. - # - # @param [String] locator - # Label, id, or name of field to match - # - def fillable_field(locator) - locator = locator.to_s - xpath = descendant(:input, :textarea)[~attr(:type).one_of('submit', 'image', 'radio', 'checkbox', 'hidden', 'file')] - xpath = locate_field(xpath, locator) - xpath - end - - - # Match any `select` element. - # - # @param [String] locator - # Label, id, or name of the field to match - # - def select(locator) - locator = locator.to_s - locate_field(descendant(:select), locator) - end - - - # Match any `input` element of type `checkbox`. - # - # @param [String] locator - # Label, id, or name of the checkbox to match - # - def checkbox(locator) - locator = locator.to_s - locate_field(descendant(:input)[attr(:type).equals('checkbox')], locator) - end - - - # Match any `input` element of type `radio`. - # - # @param [String] locator - # Label, id, or name of the radio button to match - # - def radio_button(locator) - locator = locator.to_s - locate_field(descendant(:input)[attr(:type).equals('radio')], locator) - end - - - # Match any `input` element of type `file`. - # - # @param [String] locator - # Label, id, or name of the file field to match - # - def file_field(locator) - locator = locator.to_s - locate_field(descendant(:input)[attr(:type).equals('file')], locator) - end - - - # Match an `optgroup` element. - # - # @param [String] name - # Label for the option group - # - def optgroup(locator) - locator = locator.to_s - descendant(:optgroup)[attr(:label).is(locator)] - end - - - # Match an `option` element. - # - # @param [String] name - # Visible text of the option - # - def option(locator) - locator = locator.to_s - descendant(:option)[string.n.is(locator)] - end - - - # Match any `table` element. - # - # @param [String] locator - # Caption or id of the table to match - # @option options [Array] :rows - # Content of each cell in each row to match - # - def table(locator) - locator = locator.to_s - descendant(:table)[attr(:id).equals(locator) | descendant(:caption).is(locator)] - end - - # Match any 'dd' element. - # - # @param [String] locator - # Id of the 'dd' element or text from preciding 'dt' element content - def definition_description(locator) - locator = locator.to_s - descendant(:dd)[attr(:id).equals(locator) | previous_sibling(:dt)[string.n.equals(locator)] ] - end - - protected - - def locate_field(xpath, locator) - locate_field = xpath[attr(:id).equals(locator) | attr(:name).equals(locator) | attr(:placeholder).equals(locator) | attr(:id).equals(anywhere(:label)[string.n.is(locator)].attr(:for))] - locate_field += descendant(:label)[string.n.is(locator)].descendant(xpath) - locate_field - end - end -end diff -Nru ruby-xpath-2.0.0/lib/xpath/literal.rb ruby-xpath-3.2.0/lib/xpath/literal.rb --- ruby-xpath-2.0.0/lib/xpath/literal.rb 2013-05-23 00:36:05.000000000 +0000 +++ ruby-xpath-3.2.0/lib/xpath/literal.rb 2019-01-05 15:00:16.000000000 +0000 @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module XPath class Literal attr_reader :value diff -Nru ruby-xpath-2.0.0/lib/xpath/renderer.rb ruby-xpath-3.2.0/lib/xpath/renderer.rb --- ruby-xpath-2.0.0/lib/xpath/renderer.rb 2013-05-23 00:36:05.000000000 +0000 +++ ruby-xpath-3.2.0/lib/xpath/renderer.rb 2019-01-05 15:00:16.000000000 +0000 @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module XPath class Renderer def self.render(node, type) @@ -15,11 +17,11 @@ def convert_argument(argument) case argument - when Expression, Union then render(argument) - when Array then argument.map { |element| convert_argument(element) } - when String then string_literal(argument) - when Literal then argument.value - else argument.to_s + when Expression, Union then render(argument) + when Array then argument.map { |element| convert_argument(element) } + when String then string_literal(argument) + when Literal then argument.value + else argument.to_s end end @@ -27,7 +29,7 @@ if string.include?("'") string = string.split("'", -1).map do |substr| "'#{substr}'" - end.join(%q{,"'",}) + end.join(%q(,"'",)) "concat(#{string})" else "'#{string}'" @@ -38,32 +40,20 @@ '.' end - def descendant(parent, element_names) - if element_names.length == 1 - "#{parent}//#{element_names.first}" - elsif element_names.length > 1 - "#{parent}//*[#{element_names.map { |e| "self::#{e}" }.join(" | ")}]" - else - "#{parent}//*" - end + def descendant(current, element_names) + with_element_conditions("#{current}//", element_names) end - def child(parent, element_names) - if element_names.length == 1 - "#{parent}/#{element_names.first}" - elsif element_names.length > 1 - "#{parent}/*[#{element_names.map { |e| "self::#{e}" }.join(" | ")}]" - else - "#{parent}/*" - end + def child(current, element_names) + with_element_conditions("#{current}/", element_names) end - def axis(parent, name, tag_name) - "#{parent}/#{name}::#{tag_name}" + def axis(current, name, element_names) + with_element_conditions("#{current}/#{name}::", element_names) end - def node_name(current) - "name(#{current})" + def anywhere(element_names) + with_element_conditions('//', element_names) end def where(on, condition) @@ -71,18 +61,22 @@ end def attribute(current, name) - "#{current}/@#{name}" + if valid_xml_name?(name) + "#{current}/@#{name}" + else + "#{current}/attribute::*[local-name(.) = #{string_literal(name)}]" + end end - def equality(one, two) - "#{one} = #{two}" + def binary_operator(name, left, right) + "(#{left} #{name} #{right})" end def is(one, two) if @type == :exact - equality(one, two) + binary_operator('=', one, two) else - contains(one, two) + function(:contains, one, two) end end @@ -94,10 +88,6 @@ "#{current}/text()" end - def normalized_space(current) - "normalize-space(#{current})" - end - def literal(node) node end @@ -113,62 +103,24 @@ expressions.join(' | ') end - def anywhere(element_names) - if element_names.length == 1 - "//#{element_names.first}" - elsif element_names.length > 1 - "//*[#{element_names.map { |e| "self::#{e}" }.join(" | ")}]" - else - "//*" - end - end - - def contains(current, value) - "contains(#{current}, #{value})" - end - - def starts_with(current, value) - "starts-with(#{current}, #{value})" - end - - def and(one, two) - "(#{one} and #{two})" - end - - def or(one, two) - "(#{one} or #{two})" + def function(name, *arguments) + "#{name}(#{arguments.join(', ')})" end - def one_of(current, values) - values.map { |value| "#{current} = #{value}" }.join(' or ') - end + private - def next_sibling(current, element_names) + def with_element_conditions(expression, element_names) if element_names.length == 1 - "#{current}/following-sibling::*[1]/self::#{element_names.first}" + "#{expression}#{element_names.first}" elsif element_names.length > 1 - "#{current}/following-sibling::*[1]/self::*[#{element_names.map { |e| "self::#{e}" }.join(" | ")}]" + "#{expression}*[#{element_names.map { |e| "self::#{e}" }.join(' | ')}]" else - "#{current}/following-sibling::*[1]/self::*" + "#{expression}*" end end - def previous_sibling(current, element_names) - if element_names.length == 1 - "#{current}/preceding-sibling::*[1]/self::#{element_names.first}" - elsif element_names.length > 1 - "#{current}/preceding-sibling::*[1]/self::*[#{element_names.map { |e| "self::#{e}" }.join(" | ")}]" - else - "#{current}/preceding-sibling::*[1]/self::*" - end - end - - def inverse(current) - "not(#{current})" - end - - def string_function(current) - "string(#{current})" + def valid_xml_name?(name) + name =~ /^[a-zA-Z_:][a-zA-Z0-9_:\.\-]*$/ end end end diff -Nru ruby-xpath-2.0.0/lib/xpath/union.rb ruby-xpath-3.2.0/lib/xpath/union.rb --- ruby-xpath-2.0.0/lib/xpath/union.rb 2013-05-23 00:36:05.000000000 +0000 +++ ruby-xpath-3.2.0/lib/xpath/union.rb 2019-01-05 15:00:16.000000000 +0000 @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module XPath class Union include Enumerable @@ -17,11 +19,11 @@ arguments.each(&block) end - def method_missing(*args) + def method_missing(*args) # rubocop:disable Style/MethodMissingSuper, Style/MissingRespondToMissing XPath::Union.new(*arguments.map { |e| e.send(*args) }) end - def to_xpath(type=nil) + def to_xpath(type = nil) Renderer.render(self, type) end alias_method :to_s, :to_xpath diff -Nru ruby-xpath-2.0.0/lib/xpath/version.rb ruby-xpath-3.2.0/lib/xpath/version.rb --- ruby-xpath-2.0.0/lib/xpath/version.rb 2013-05-23 00:36:05.000000000 +0000 +++ ruby-xpath-3.2.0/lib/xpath/version.rb 2019-01-05 15:00:16.000000000 +0000 @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module XPath - VERSION = '2.0.0' + VERSION = '3.2.0' end diff -Nru ruby-xpath-2.0.0/lib/xpath.rb ruby-xpath-3.2.0/lib/xpath.rb --- ruby-xpath-2.0.0/lib/xpath.rb 2013-05-23 00:36:05.000000000 +0000 +++ ruby-xpath-3.2.0/lib/xpath.rb 2019-01-05 15:00:16.000000000 +0000 @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'nokogiri' require 'xpath/dsl' @@ -5,12 +7,10 @@ require 'xpath/literal' require 'xpath/union' require 'xpath/renderer' -require 'xpath/html' module XPath - - extend XPath::DSL::TopLevel - include XPath::DSL::TopLevel + extend XPath::DSL + include XPath::DSL def self.generate yield(self) diff -Nru ruby-xpath-2.0.0/metadata.gz.sig ruby-xpath-3.2.0/metadata.gz.sig --- ruby-xpath-2.0.0/metadata.gz.sig 2013-05-23 00:36:05.000000000 +0000 +++ ruby-xpath-3.2.0/metadata.gz.sig 1970-01-01 00:00:00.000000000 +0000 @@ -1 +0,0 @@ -Qיִ.ChiΑj5hg/Ϋ!7z4 - - !ruby/object:Gem::Version - version: '1.3' - type: :runtime - prerelease: false - version_requirements: !ruby/object:Gem::Requirement - none: false - requirements: - - - ~> - - !ruby/object:Gem::Version - version: '1.3' -- !ruby/object:Gem::Dependency - name: rspec - requirement: !ruby/object:Gem::Requirement - none: false - requirements: - - - ~> - - !ruby/object:Gem::Version - version: '2.0' - type: :development - prerelease: false - version_requirements: !ruby/object:Gem::Requirement - none: false - requirements: - - - ~> - - !ruby/object:Gem::Version - version: '2.0' -- !ruby/object:Gem::Dependency - name: yard - requirement: !ruby/object:Gem::Requirement - none: false - requirements: - - - ! '>=' - - !ruby/object:Gem::Version - version: 0.5.8 - type: :development - prerelease: false - version_requirements: !ruby/object:Gem::Requirement - none: false - requirements: - - - ! '>=' - - !ruby/object:Gem::Version - version: 0.5.8 -- !ruby/object:Gem::Dependency - name: rake - requirement: !ruby/object:Gem::Requirement - none: false - requirements: - - - ! '>=' - - !ruby/object:Gem::Version - version: '0' - type: :development - prerelease: false - version_requirements: !ruby/object:Gem::Requirement - none: false - requirements: - - - ! '>=' - - !ruby/object:Gem::Version - version: '0' -description: XPath is a Ruby DSL for generating XPath expressions -email: -- jonas.nicklas@gmail.com -executables: [] -extensions: [] -extra_rdoc_files: -- README.md -files: -- lib/xpath/dsl.rb -- lib/xpath/expression.rb -- lib/xpath/html.rb -- lib/xpath/literal.rb -- lib/xpath/renderer.rb -- lib/xpath/union.rb -- lib/xpath/version.rb -- lib/xpath.rb -- spec/fixtures/form.html -- spec/fixtures/simple.html -- spec/fixtures/stuff.html -- spec/html_spec.rb -- spec/spec_helper.rb -- spec/union_spec.rb -- spec/xpath_spec.rb -- README.md -homepage: http://github.com/jnicklas/xpath -licenses: [] -post_install_message: -rdoc_options: -- --main -- README.md -require_paths: -- lib -required_ruby_version: !ruby/object:Gem::Requirement - none: false - requirements: - - - ! '>=' - - !ruby/object:Gem::Version - version: '0' -required_rubygems_version: !ruby/object:Gem::Requirement - none: false - requirements: - - - ! '>=' - - !ruby/object:Gem::Version - version: '0' -requirements: [] -rubyforge_project: xpath -rubygems_version: 1.8.25 -signing_key: -specification_version: 3 -summary: Generate XPath expressions from Ruby -test_files: [] -has_rdoc: diff -Nru ruby-xpath-2.0.0/README.md ruby-xpath-3.2.0/README.md --- ruby-xpath-2.0.0/README.md 2013-05-23 00:36:05.000000000 +0000 +++ ruby-xpath-3.2.0/README.md 2019-01-05 15:00:16.000000000 +0000 @@ -3,7 +3,8 @@ XPath is a Ruby DSL around a subset of XPath 1.0. Its primary purpose is to facilitate writing complex XPath queries from Ruby code. -[![Build Status](https://secure.travis-ci.org/jnicklas/xpath.png?branch=master)](http://travis-ci.org/jnicklas/xpath) +[![Gem Version](https://badge.fury.io/rb/xpath.png)](http://badge.fury.io/rb/xpath) +[![Build Status](https://secure.travis-ci.org/teamcapybara/xpath.png?branch=master)](http://travis-ci.org/teamcapybara/xpath) ## Generating expressions @@ -36,11 +37,9 @@ end ``` -Both ways return an -[`XPath::Expression`](http://rdoc.info/github/jnicklas/xpath/XPath/Expression) -instance, which can be further modified. To convert the expression to a -string, just call `#to_s` on it. All available expressions are defined in -[`XPath::DSL`](http://rdoc.info/github/jnicklas/xpath/XPath/DSL). +Both ways return an `XPath::Expression` instance, which can be further +modified. To convert the expression to a string, just call `#to_s` on it. All +available expressions are defined in `XPath::DSL`. ## String, Hashes and Symbols @@ -74,63 +73,6 @@ Keep in mind that XPath is 1-indexed and not 0-indexed like most other programming languages, including Ruby. -Hashes are automatically converted to equality expressions, so the above -example could be written as: - -``` ruby -XPath.descendant(:p)[:@id => 'foo'] -``` - -Which would generate the same expression: - -``` -.//p[@id = 'foo'] -``` - -Note that the same rules apply here, both the keys and values in the hash are -treated the same way as any other expression in XPath. Thus the following are -not equivalent: - -``` ruby -XPath.descendant(:p)[:@id => 'foo'] # => .//p[@id = 'foo'] -XPath.descendant(:p)[:id => 'foo'] # => .//p[id = 'foo'] -XPath.descendant(:p)['id' => 'foo'] # => .//p['id' = 'foo'] -``` - -## HTML - -XPath comes with a set of premade XPaths for use with HTML documents. - -You can generate these like this: - -``` ruby -XPath::HTML.link('Home') -XPath::HTML.field('Name') -``` - -See [`XPath::HTML`](http://rdoc.info/github/jnicklas/xpath/XPath/HTML) for all -available matchers. - ## License -(The MIT License) - -Copyright © 2010 Jonas Nicklas - -Permission is hereby granted, free of charge, to any person obtaining a copy of -this software and associated documentation files (the ‘Software’), to deal in -the Software without restriction, including without limitation the rights to -use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies -of the Software, and to permit persons to whom the Software is furnished to do -so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED ‘AS IS’, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. +See [LICENSE](LICENSE). diff -Nru ruby-xpath-2.0.0/spec/fixtures/simple.html ruby-xpath-3.2.0/spec/fixtures/simple.html --- ruby-xpath-2.0.0/spec/fixtures/simple.html 2013-05-23 00:36:05.000000000 +0000 +++ ruby-xpath-3.2.0/spec/fixtures/simple.html 2019-01-05 15:00:16.000000000 +0000 @@ -17,7 +17,7 @@
  • A list
-

Bax

+

Bax

Bax

Blah

@@ -26,7 +26,7 @@

allamas

-

llama

+

llama

@@ -37,9 +37,17 @@

-

chimp

+

chimp

elephant

flamingo

+ + Hello there + + Hello there + +
+

Blah

+
diff -Nru ruby-xpath-2.0.0/spec/html_spec.rb ruby-xpath-3.2.0/spec/html_spec.rb --- ruby-xpath-2.0.0/spec/html_spec.rb 2013-05-23 00:36:05.000000000 +0000 +++ ruby-xpath-3.2.0/spec/html_spec.rb 1970-01-01 00:00:00.000000000 +0000 @@ -1,308 +0,0 @@ -require 'spec_helper' -require 'nokogiri' - -describe XPath::HTML do - let(:template) { 'form' } - let(:template_path) { File.read(File.expand_path("fixtures/#{template}.html", File.dirname(__FILE__))) } - let(:doc) { Nokogiri::HTML(template_path) } - - def get(*args) - all(*args).first - end - - def all(*args) - type = example.metadata[:type] - doc.xpath(XPath::HTML.send(subject, *args).to_xpath(type)).map { |node| node[:data] } - end - - describe '#link' do - subject { :link } - - it("finds links by id") { get('some-id').should == 'link-id' } - it("finds links by content") { get('An awesome link').should == 'link-text' } - it("finds links by content regardless of whitespace") { get('My whitespaced link').should == 'link-whitespace' } - it("finds links with child tags by content") { get('An emphatic link').should == 'link-children' } - it("finds links by the content of their child tags") { get('emphatic').should == 'link-children' } - it("finds links by approximate content") { get('awesome').should == 'link-text' } - it("finds links by title") { get('My title').should == 'link-title' } - it("finds links by approximate title") { get('title').should == 'link-title' } - it("finds links by image's alt attribute") { get('Alt link').should == 'link-img' } - it("finds links by image's approximate alt attribute") { get('Alt').should == 'link-img' } - it("does not find links without href attriutes") { get('Wrong Link').should be_nil } - it("casts to string") { get(:'some-id').should == 'link-id' } - - context "with exact match", :type => :exact do - it("finds links by content") { get('An awesome link').should == 'link-text' } - it("does not find links by approximate content") { get('awesome').should be_nil } - it("finds links by title") { get('My title').should == 'link-title' } - it("does not find links by approximate title") { get('title').should be_nil } - it("finds links by image's alt attribute") { get('Alt link').should == 'link-img' } - it("does not find links by image's approximate alt attribute") { get('Alt').should be_nil } - end - end - - describe '#button' do - subject { :button } - - context "with submit type" do - it("finds buttons by id") { get('submit-with-id').should == 'id-submit' } - it("finds buttons by value") { get('submit-with-value').should == 'value-submit' } - it("finds buttons by approximate value") { get('mit-with-val').should == 'value-submit' } - it("finds buttons by title") { get('My submit title').should == 'title-submit' } - it("finds buttons by approximate title") { get('submit title').should == 'title-submit' } - - context "with exact match", :type => :exact do - it("finds buttons by value") { get('submit-with-value').should == 'value-submit' } - it("does not find buttons by approximate value") { get('mit-with-val').should be_nil } - it("finds buttons by title") { get('My submit title').should == 'title-submit' } - it("does not find buttons by approximate title") { get('submit title').should be_nil } - end - end - - context "with reset type" do - it("finds buttons by id") { get('reset-with-id').should == 'id-reset' } - it("finds buttons by value") { get('reset-with-value').should == 'value-reset' } - it("finds buttons by approximate value") { get('set-with-val').should == 'value-reset' } - it("finds buttons by title") { get('My reset title').should == 'title-reset' } - it("finds buttons by approximate title") { get('reset title').should == 'title-reset' } - - context "with exact match", :type => :exact do - it("finds buttons by value") { get('reset-with-value').should == 'value-reset' } - it("does not find buttons by approximate value") { get('set-with-val').should be_nil } - it("finds buttons by title") { get('My reset title').should == 'title-reset' } - it("does not find buttons by approximate title") { get('reset title').should be_nil } - end - end - - context "with button type" do - it("finds buttons by id") { get('button-with-id').should == 'id-button' } - it("finds buttons by value") { get('button-with-value').should == 'value-button' } - it("finds buttons by approximate value") { get('ton-with-val').should == 'value-button' } - it("finds buttons by title") { get('My button title').should == 'title-button' } - it("finds buttons by approximate title") { get('button title').should == 'title-button' } - - context "with exact match", :type => :exact do - it("finds buttons by value") { get('button-with-value').should == 'value-button' } - it("does not find buttons by approximate value") { get('ton-with-val').should be_nil } - it("finds buttons by title") { get('My button title').should == 'title-button' } - it("does not find buttons by approximate title") { get('button title').should be_nil } - end - end - - context "with image type" do - it("finds buttons by id") { get('imgbut-with-id').should == 'id-imgbut' } - it("finds buttons by value") { get('imgbut-with-value').should == 'value-imgbut' } - it("finds buttons by approximate value") { get('gbut-with-val').should == 'value-imgbut' } - it("finds buttons by alt attribute") { get('imgbut-with-alt').should == 'alt-imgbut' } - it("finds buttons by approximate alt attribute") { get('mgbut-with-al').should == 'alt-imgbut' } - it("finds buttons by title") { get('My imgbut title').should == 'title-imgbut' } - it("finds buttons by approximate title") { get('imgbut title').should == 'title-imgbut' } - - context "with exact match", :type => :exact do - it("finds buttons by value") { get('imgbut-with-value').should == 'value-imgbut' } - it("does not find buttons by approximate value") { get('gbut-with-val').should be_nil } - it("finds buttons by alt attribute") { get('imgbut-with-alt').should == 'alt-imgbut' } - it("does not find buttons by approximate alt attribute") { get('mgbut-with-al').should be_nil } - it("finds buttons by title") { get('My imgbut title').should == 'title-imgbut' } - it("does not find buttons by approximate title") { get('imgbut title').should be_nil } - end - end - - context "with button tag" do - it("finds buttons by id") { get('btag-with-id').should == 'id-btag' } - it("finds buttons by value") { get('btag-with-value').should == 'value-btag' } - it("finds buttons by approximate value") { get('tag-with-val').should == 'value-btag' } - it("finds buttons by text") { get('btag-with-text').should == 'text-btag' } - it("finds buttons by text ignoring whitespace") { get('My whitespaced button').should == 'btag-with-whitespace' } - it("finds buttons by approximate text ") { get('tag-with-tex').should == 'text-btag' } - it("finds buttons with child tags by text") { get('An emphatic button').should == 'btag-with-children' } - it("finds buttons by text of their children") { get('emphatic').should == 'btag-with-children' } - it("finds buttons by title") { get('My btag title').should == 'title-btag' } - it("finds buttons by approximate title") { get('btag title').should == 'title-btag' } - - context "with exact match", :type => :exact do - it("finds buttons by value") { get('btag-with-value').should == 'value-btag' } - it("does not find buttons by approximate value") { get('tag-with-val').should be_nil } - it("finds buttons by text") { get('btag-with-text').should == 'text-btag' } - it("does not find buttons by approximate text ") { get('tag-with-tex').should be_nil } - it("finds buttons by title") { get('My btag title').should == 'title-btag' } - it("does not find buttons by approximate title") { get('btag title').should be_nil } - end - end - - context "with unkown type" do - it("does not find the button") { get('schmoo button').should be_nil } - end - - it("casts to string") { get(:'tag-with-tex').should == 'text-btag' } - end - - describe '#fieldset' do - subject { :fieldset } - - it("finds fieldsets by id") { get('some-fieldset-id').should == 'fieldset-id' } - it("finds fieldsets by legend") { get('Some Legend').should == 'fieldset-legend' } - it("finds fieldsets by legend child tags") { get('Span Legend').should == 'fieldset-legend-span' } - it("accepts approximate legends") { get('Legend').should == 'fieldset-legend' } - it("finds nested fieldsets by legend") { get('Inner legend').should == 'fieldset-inner' } - it("casts to string") { get(:'Inner legend').should == 'fieldset-inner' } - - context "with exact match", :type => :exact do - it("finds fieldsets by legend") { get('Some Legend').should == 'fieldset-legend' } - it("does not find by approximate legends") { get('Legend').should be_nil } - end - end - - describe '#field' do - subject { :field } - - context "by id" do - it("finds inputs with no type") { get('input-with-id').should == 'input-with-id-data' } - it("finds inputs with text type") { get('input-text-with-id').should == 'input-text-with-id-data' } - it("finds inputs with password type") { get('input-password-with-id').should == 'input-password-with-id-data' } - it("finds inputs with custom type") { get('input-custom-with-id').should == 'input-custom-with-id-data' } - it("finds textareas") { get('textarea-with-id').should == 'textarea-with-id-data' } - it("finds select boxes") { get('select-with-id').should == 'select-with-id-data' } - it("does not find submit buttons") { get('input-submit-with-id').should be_nil } - it("does not find image buttons") { get('input-image-with-id').should be_nil } - it("does not find hidden fields") { get('input-hidden-with-id').should be_nil } - end - - context "by name" do - it("finds inputs with no type") { get('input-with-name').should == 'input-with-name-data' } - it("finds inputs with text type") { get('input-text-with-name').should == 'input-text-with-name-data' } - it("finds inputs with password type") { get('input-password-with-name').should == 'input-password-with-name-data' } - it("finds inputs with custom type") { get('input-custom-with-name').should == 'input-custom-with-name-data' } - it("finds textareas") { get('textarea-with-name').should == 'textarea-with-name-data' } - it("finds select boxes") { get('select-with-name').should == 'select-with-name-data' } - it("does not find submit buttons") { get('input-submit-with-name').should be_nil } - it("does not find image buttons") { get('input-image-with-name').should be_nil } - it("does not find hidden fields") { get('input-hidden-with-name').should be_nil } - end - - context "by placeholder" do - it("finds inputs with no type") { get('input-with-placeholder').should == 'input-with-placeholder-data' } - it("finds inputs with text type") { get('input-text-with-placeholder').should == 'input-text-with-placeholder-data' } - it("finds inputs with password type") { get('input-password-with-placeholder').should == 'input-password-with-placeholder-data' } - it("finds inputs with custom type") { get('input-custom-with-placeholder').should == 'input-custom-with-placeholder-data' } - it("finds textareas") { get('textarea-with-placeholder').should == 'textarea-with-placeholder-data' } - it("does not find hidden fields") { get('input-hidden-with-placeholder').should be_nil } - end - - context "by referenced label" do - it("finds inputs with no type") { get('Input with label').should == 'input-with-label-data' } - it("finds inputs with text type") { get('Input text with label').should == 'input-text-with-label-data' } - it("finds inputs with password type") { get('Input password with label').should == 'input-password-with-label-data' } - it("finds inputs with custom type") { get('Input custom with label').should == 'input-custom-with-label-data' } - it("finds textareas") { get('Textarea with label').should == 'textarea-with-label-data' } - it("finds select boxes") { get('Select with label').should == 'select-with-label-data' } - it("does not find submit buttons") { get('Input submit with label').should be_nil } - it("does not find image buttons") { get('Input image with label').should be_nil } - it("does not find hidden fields") { get('Input hidden with label').should be_nil } - end - - context "by parent label" do - it("finds inputs with no type") { get('Input with parent label').should == 'input-with-parent-label-data' } - it("finds inputs with text type") { get('Input text with parent label').should == 'input-text-with-parent-label-data' } - it("finds inputs with password type") { get('Input password with parent label').should == 'input-password-with-parent-label-data' } - it("finds inputs with custom type") { get('Input custom with parent label').should == 'input-custom-with-parent-label-data' } - it("finds textareas") { get('Textarea with parent label').should == 'textarea-with-parent-label-data' } - it("finds select boxes") { get('Select with parent label').should == 'select-with-parent-label-data' } - it("does not find submit buttons") { get('Input submit with parent label').should be_nil } - it("does not find image buttons") { get('Input image with parent label').should be_nil } - it("does not find hidden fields") { get('Input hidden with parent label').should be_nil } - end - - it("casts to string") { get(:'select-with-id').should == 'select-with-id-data' } - end - - describe '#fillable_field' do - subject{ :fillable_field } - context "by parent label" do - it("finds inputs with text type") { get('Label text').should == 'id-text' } - it("finds inputs where label has problem chars") { get("Label text's got an apostrophe").should == 'id-problem-text' } - end - - end - - describe '#select' do - subject{ :select } - it("finds selects by id") { get('select-with-id').should == 'select-with-id-data' } - it("finds selects by name") { get('select-with-name').should == 'select-with-name-data' } - it("finds selects by label") { get('Select with label').should == 'select-with-label-data' } - it("finds selects by parent label") { get('Select with parent label').should == 'select-with-parent-label-data' } - it("casts to string") { get(:'Select with parent label').should == 'select-with-parent-label-data' } - end - - describe '#checkbox' do - subject{ :checkbox } - it("finds checkboxes by id") { get('input-checkbox-with-id').should == 'input-checkbox-with-id-data' } - it("finds checkboxes by name") { get('input-checkbox-with-name').should == 'input-checkbox-with-name-data' } - it("finds checkboxes by label") { get('Input checkbox with label').should == 'input-checkbox-with-label-data' } - it("finds checkboxes by parent label") { get('Input checkbox with parent label').should == 'input-checkbox-with-parent-label-data' } - it("casts to string") { get(:'Input checkbox with parent label').should == 'input-checkbox-with-parent-label-data' } - end - - describe '#radio_button' do - subject{ :radio_button } - it("finds radio buttons by id") { get('input-radio-with-id').should == 'input-radio-with-id-data' } - it("finds radio buttons by name") { get('input-radio-with-name').should == 'input-radio-with-name-data' } - it("finds radio buttons by label") { get('Input radio with label').should == 'input-radio-with-label-data' } - it("finds radio buttons by parent label") { get('Input radio with parent label').should == 'input-radio-with-parent-label-data' } - it("casts to string") { get(:'Input radio with parent label').should == 'input-radio-with-parent-label-data' } - end - - describe '#file_field' do - subject{ :file_field } - it("finds file fields by id") { get('input-file-with-id').should == 'input-file-with-id-data' } - it("finds file fields by name") { get('input-file-with-name').should == 'input-file-with-name-data' } - it("finds file fields by label") { get('Input file with label').should == 'input-file-with-label-data' } - it("finds file fields by parent label") { get('Input file with parent label').should == 'input-file-with-parent-label-data' } - it("casts to string") { get(:'Input file with parent label').should == 'input-file-with-parent-label-data' } - end - - describe "#optgroup" do - subject { :optgroup } - it("finds optgroups by label") { get('Group A').should == 'optgroup-a' } - it("finds optgroups by approximate label") { get('oup A').should == 'optgroup-a' } - it("casts to string") { get(:'Group A').should == 'optgroup-a' } - - context "with exact match", :type => :exact do - it("finds by label") { get('Group A').should == 'optgroup-a' } - it("does not find by approximate label") { get('oup A').should be_nil } - end - end - - describe '#option' do - subject{ :option } - it("finds by text") { get('Option with text').should == 'option-with-text-data' } - it("finds by approximate text") { get('Option with').should == 'option-with-text-data' } - it("casts to string") { get(:'Option with text').should == 'option-with-text-data' } - - context "with exact match", :type => :exact do - it("finds by text") { get('Option with text').should == 'option-with-text-data' } - it("does not find by approximate text") { get('Option with').should be_nil } - end - end - - describe "#table" do - subject {:table} - it("finds by id") { get('table-with-id').should == 'table-with-id-data' } - it("finds by caption") { get('Table with caption').should == 'table-with-caption-data' } - it("finds by approximate caption") { get('Table with').should == 'table-with-caption-data' } - it("casts to string") { get(:'Table with caption').should == 'table-with-caption-data' } - - context "with exact match", :type => :exact do - it("finds by caption") { get('Table with caption').should == 'table-with-caption-data' } - it("does not find by approximate caption") { get('Table with').should be_nil } - end - end - - describe "#definition_description" do - subject {:definition_description} - let(:template) {'stuff'} - it("find definition description by id") { get('latte').should == "with-id" } - it("find definition description by term") { get("Milk").should == "with-dt" } - it("casts to string") { get(:"Milk").should == "with-dt" } - end -end diff -Nru ruby-xpath-2.0.0/spec/spec_helper.rb ruby-xpath-3.2.0/spec/spec_helper.rb --- ruby-xpath-2.0.0/spec/spec_helper.rb 2013-05-23 00:36:05.000000000 +0000 +++ ruby-xpath-3.2.0/spec/spec_helper.rb 2019-01-05 15:00:16.000000000 +0000 @@ -1 +1,8 @@ +# frozen_string_literal: true + require 'xpath' +require 'pry' + +RSpec.configure do |config| + config.expect_with(:rspec) { |c| c.syntax = :should } +end diff -Nru ruby-xpath-2.0.0/spec/union_spec.rb ruby-xpath-3.2.0/spec/union_spec.rb --- ruby-xpath-2.0.0/spec/union_spec.rb 2013-05-23 00:36:05.000000000 +0000 +++ ruby-xpath-3.2.0/spec/union_spec.rb 2019-01-05 15:00:16.000000000 +0000 @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe XPath::Union do @@ -5,60 +7,57 @@ let(:doc) { Nokogiri::HTML(template) } describe '#expressions' do - it "should return the expressions" do + it 'should return the expressions' do @expr1 = XPath.generate { |x| x.descendant(:p) } @expr2 = XPath.generate { |x| x.descendant(:div) } @collection = XPath::Union.new(@expr1, @expr2) - @collection.expressions.should == [@expr1, @expr2] + @collection.expressions.should eq [@expr1, @expr2] end end describe '#each' do - it "should iterate through the expressions" do + it 'should iterate through the expressions' do @expr1 = XPath.generate { |x| x.descendant(:p) } @expr2 = XPath.generate { |x| x.descendant(:div) } @collection = XPath::Union.new(@expr1, @expr2) exprs = [] @collection.each { |expr| exprs << expr } - exprs.should == [@expr1, @expr2] + exprs.should eq [@expr1, @expr2] end end describe '#map' do - it "should map the expressions" do + it 'should map the expressions' do @expr1 = XPath.generate { |x| x.descendant(:p) } @expr2 = XPath.generate { |x| x.descendant(:div) } @collection = XPath::Union.new(@expr1, @expr2) - @collection.map { |expr| expr.expression }.should == [:descendant, :descendant] + @collection.map(&:expression).should eq %i[descendant descendant] end end describe '#to_xpath' do - it "should create a valid xpath expression" do + it 'should create a valid xpath expression' do @expr1 = XPath.generate { |x| x.descendant(:p) } @expr2 = XPath.generate { |x| x.descendant(:div).where(x.attr(:id) == 'foo') } @collection = XPath::Union.new(@expr1, @expr2) @results = doc.xpath(@collection.to_xpath) - @results[0][:title].should == 'fooDiv' - @results[1].text.should == 'Blah' - @results[2].text.should == 'Bax' + @results[0][:title].should eq 'fooDiv' + @results[1].text.should eq 'Blah' + @results[2].text.should eq 'Bax' end end - describe '#where and others' do - it "should be delegated to the individual expressions" do + it 'should be delegated to the individual expressions' do @expr1 = XPath.generate { |x| x.descendant(:p) } @expr2 = XPath.generate { |x| x.descendant(:div) } @collection = XPath::Union.new(@expr1, @expr2) @xpath1 = @collection.where(XPath.attr(:id) == 'foo').to_xpath @xpath2 = @collection.where(XPath.attr(:id) == 'fooDiv').to_xpath @results = doc.xpath(@xpath1) - @results[0][:title].should == 'fooDiv' + @results[0][:title].should eq 'fooDiv' @results = doc.xpath(@xpath2) - @results[0][:id].should == 'fooDiv' + @results[0][:id].should eq 'fooDiv' end end - end - diff -Nru ruby-xpath-2.0.0/spec/xpath_spec.rb ruby-xpath-3.2.0/spec/xpath_spec.rb --- ruby-xpath-2.0.0/spec/xpath_spec.rb 2013-05-23 00:36:05.000000000 +0000 +++ ruby-xpath-3.2.0/spec/xpath_spec.rb 2019-01-05 15:00:16.000000000 +0000 @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' require 'nokogiri' @@ -14,23 +16,23 @@ let(:template) { File.read(File.expand_path('fixtures/simple.html', File.dirname(__FILE__))) } let(:doc) { Nokogiri::HTML(template) } - def xpath(type=nil, &block) + def xpath(type = nil, &block) doc.xpath XPath.generate(&block).to_xpath(type) end - it "should work as a mixin" do + it 'should work as a mixin' do xpath = Thingy.new.foo_div.to_xpath - doc.xpath(xpath).first[:title].should == 'fooDiv' + doc.xpath(xpath).first[:title].should eq 'fooDiv' end describe '#descendant' do - it "should find nodes that are nested below the current node" do + it 'should find nodes that are nested below the current node' do @results = xpath { |x| x.descendant(:p) } - @results[0].text.should == "Blah" - @results[1].text.should == "Bax" + @results[0].text.should eq 'Blah' + @results[1].text.should eq 'Bax' end - it "should not find nodes outside the context" do + it 'should not find nodes outside the context' do @results = xpath do |x| foo_div = x.descendant(:div).where(x.attr(:id) == 'foo') x.descendant(:p).where(x.attr(:id) == foo_div.attr(:title)) @@ -38,312 +40,523 @@ @results[0].should be_nil end - it "should find multiple kinds of nodes" do + it 'should find multiple kinds of nodes' do @results = xpath { |x| x.descendant(:p, :ul) } - @results[0].text.should == 'Blah' - @results[3].text.should == 'A list' + @results[0].text.should eq 'Blah' + @results[3].text.should eq 'A list' end - it "should find all nodes when no arguments given" do + it 'should find all nodes when no arguments given' do @results = xpath { |x| x.descendant[x.attr(:id) == 'foo'].descendant } - @results[0].text.should == 'Blah' - @results[4].text.should == 'A list' + @results[0].text.should eq 'Blah' + @results[4].text.should eq 'A list' end end describe '#child' do - it "should find nodes that are nested directly below the current node" do + it 'should find nodes that are nested directly below the current node' do @results = xpath { |x| x.descendant(:div).child(:p) } - @results[0].text.should == "Blah" - @results[1].text.should == "Bax" + @results[0].text.should eq 'Blah' + @results[1].text.should eq 'Bax' end - it "should not find nodes that are nested further down below the current node" do + it 'should not find nodes that are nested further down below the current node' do @results = xpath { |x| x.child(:p) } @results[0].should be_nil end - it "should find multiple kinds of nodes" do + it 'should find multiple kinds of nodes' do @results = xpath { |x| x.descendant(:div).child(:p, :ul) } - @results[0].text.should == 'Blah' - @results[3].text.should == 'A list' + @results[0].text.should eq 'Blah' + @results[3].text.should eq 'A list' end - it "should find all nodes when no arguments given" do + it 'should find all nodes when no arguments given' do @results = xpath { |x| x.descendant[x.attr(:id) == 'foo'].child } - @results[0].text.should == 'Blah' - @results[3].text.should == 'A list' + @results[0].text.should eq 'Blah' + @results[3].text.should eq 'A list' end end describe '#axis' do - it "should find nodes given the xpath axis" do + it 'should find nodes given the xpath axis' do @results = xpath { |x| x.axis(:descendant, :p) } - @results[0].text.should == "Blah" + @results[0].text.should eq 'Blah' end - it "should find nodes given the xpath axis without a specific tag" do + it 'should find nodes given the xpath axis without a specific tag' do @results = xpath { |x| x.descendant(:div)[x.attr(:id) == 'foo'].axis(:descendant) } - @results[0][:id].should == "fooDiv" + @results[0][:id].should eq 'fooDiv' end end describe '#next_sibling' do - it "should find nodes which are immediate siblings of the current node" do - xpath { |x| x.descendant(:p)[x.attr(:id) == 'fooDiv'].next_sibling(:p) }.first.text.should == 'Bax' - xpath { |x| x.descendant(:p)[x.attr(:id) == 'fooDiv'].next_sibling(:ul, :p) }.first.text.should == 'Bax' - xpath { |x| x.descendant(:p)[x.attr(:title) == 'monkey'].next_sibling(:ul, :p) }.first.text.should == 'A list' + it 'should find nodes which are immediate siblings of the current node' do + xpath { |x| x.descendant(:p)[x.attr(:id) == 'fooDiv'].next_sibling(:p) }.first.text.should eq 'Bax' + xpath { |x| x.descendant(:p)[x.attr(:id) == 'fooDiv'].next_sibling(:ul, :p) }.first.text.should eq 'Bax' + xpath { |x| x.descendant(:p)[x.attr(:title) == 'monkey'].next_sibling(:ul, :p) }.first.text.should eq 'A list' xpath { |x| x.descendant(:p)[x.attr(:id) == 'fooDiv'].next_sibling(:ul, :li) }.first.should be_nil - xpath { |x| x.descendant(:p)[x.attr(:id) == 'fooDiv'].next_sibling }.first.text.should == 'Bax' + xpath { |x| x.descendant(:p)[x.attr(:id) == 'fooDiv'].next_sibling }.first.text.should eq 'Bax' end end describe '#previous_sibling' do - it "should find nodes which are exactly preceding the current node" do - xpath { |x| x.descendant(:p)[x.attr(:id) == 'wooDiv'].previous_sibling(:p) }.first.text.should == 'Bax' - xpath { |x| x.descendant(:p)[x.attr(:id) == 'wooDiv'].previous_sibling(:ul, :p) }.first.text.should == 'Bax' - xpath { |x| x.descendant(:p)[x.attr(:title) == 'gorilla'].previous_sibling(:ul, :p) }.first.text.should == 'A list' + it 'should find nodes which are exactly preceding the current node' do + xpath { |x| x.descendant(:p)[x.attr(:id) == 'wooDiv'].previous_sibling(:p) }.first.text.should eq 'Bax' + xpath { |x| x.descendant(:p)[x.attr(:id) == 'wooDiv'].previous_sibling(:ul, :p) }.first.text.should eq 'Bax' + xpath { |x| x.descendant(:p)[x.attr(:title) == 'gorilla'].previous_sibling(:ul, :p) }.first.text.should eq 'A list' xpath { |x| x.descendant(:p)[x.attr(:id) == 'wooDiv'].previous_sibling(:ul, :li) }.first.should be_nil - xpath { |x| x.descendant(:p)[x.attr(:id) == 'wooDiv'].previous_sibling }.first.text.should == 'Bax' + xpath { |x| x.descendant(:p)[x.attr(:id) == 'wooDiv'].previous_sibling }.first.text.should eq 'Bax' end end describe '#anywhere' do - it "should find nodes regardless of the context" do + it 'should find nodes regardless of the context' do @results = xpath do |x| foo_div = x.anywhere(:div).where(x.attr(:id) == 'foo') x.descendant(:p).where(x.attr(:id) == foo_div.attr(:title)) end - @results[0].text.should == "Blah" + @results[0].text.should eq 'Blah' end - it "should find multiple kinds of nodes regardless of the context" do + it 'should find multiple kinds of nodes regardless of the context' do @results = xpath do |x| - context=x.descendant(:div).where(x.attr(:id)=='woo') + context = x.descendant(:div).where(x.attr(:id) == 'woo') context.anywhere(:p, :ul) end - @results[0].text.should == 'Blah' - @results[3].text.should == 'A list' - @results[4].text.should == 'A list' - @results[6].text.should == 'Bax' + @results[0].text.should eq 'Blah' + @results[3].text.should eq 'A list' + @results[4].text.should eq 'A list' + @results[6].text.should eq 'Bax' end - it "should find all nodes when no arguments given regardless of the context" do + it 'should find all nodes when no arguments given regardless of the context' do @results = xpath do |x| - context=x.descendant(:div).where(x.attr(:id)=='woo') + context = x.descendant(:div).where(x.attr(:id) == 'woo') context.anywhere end - @results[0].name.should == 'html' - @results[1].name.should == 'head' - @results[2].name.should == 'body' - @results[6].text.should == 'Blah' - @results[10].text.should == 'A list' - @results[13].text.should == 'A list' - @results[15].text.should == 'Bax' + @results[0].name.should eq 'html' + @results[1].name.should eq 'head' + @results[2].name.should eq 'body' + @results[6].text.should eq 'Blah' + @results[10].text.should eq 'A list' + @results[13].text.should eq 'A list' + @results[15].text.should eq 'Bax' end - end describe '#contains' do - it "should find nodes that contain the given string" do + it 'should find nodes that contain the given string' do @results = xpath do |x| x.descendant(:div).where(x.attr(:title).contains('ooD')) end - @results[0][:id].should == "foo" + @results[0][:id].should eq 'foo' end - it "should find nodes that contain the given expression" do + it 'should find nodes that contain the given expression' do @results = xpath do |x| expression = x.anywhere(:div).where(x.attr(:title) == 'fooDiv').attr(:id) x.descendant(:div).where(x.attr(:title).contains(expression)) end - @results[0][:id].should == "foo" + @results[0][:id].should eq 'foo' + end + end + + describe '#contains_word' do + it 'should find nodes that contain the given word in its entirety' do + @results = xpath do |x| + x.descendant.where(x.attr(:class).contains_word('fish')) + end + @results[0].text.should eq 'Bax' + @results[1].text.should eq 'llama' + @results.length.should eq 2 end end describe '#starts_with' do - it "should find nodes that begin with the given string" do + it 'should find nodes that begin with the given string' do @results = xpath do |x| x.descendant(:*).where(x.attr(:id).starts_with('foo')) end - @results.size.should == 2 - @results[0][:id].should == "foo" - @results[1][:id].should == "fooDiv" + @results.size.should eq 2 + @results[0][:id].should eq 'foo' + @results[1][:id].should eq 'fooDiv' end - it "should find nodes that contain the given expression" do + it 'should find nodes that contain the given expression' do @results = xpath do |x| expression = x.anywhere(:div).where(x.attr(:title) == 'fooDiv').attr(:id) x.descendant(:div).where(x.attr(:title).starts_with(expression)) end - @results[0][:id].should == "foo" + @results[0][:id].should eq 'foo' + end + end + + describe '#ends_with' do + it 'should find nodes that end with the given string' do + @results = xpath do |x| + x.descendant(:*).where(x.attr(:id).ends_with('oof')) + end + @results.size.should eq 2 + @results[0][:id].should eq 'oof' + @results[1][:id].should eq 'viDoof' + end + + it 'should find nodes that contain the given expression' do + @results = xpath do |x| + expression = x.anywhere(:div).where(x.attr(:title) == 'viDoof').attr(:id) + x.descendant(:div).where(x.attr(:title).ends_with(expression)) + end + @results[0][:id].should eq 'oof' + end + end + + describe '#uppercase' do + it 'should match uppercased text' do + @results = xpath do |x| + x.descendant(:div).where(x.attr(:title).uppercase == 'VIDOOF') + end + @results[0][:id].should eq 'oof' + end + end + + describe '#lowercase' do + it 'should match lowercased text' do + @results = xpath do |x| + x.descendant(:div).where(x.attr(:title).lowercase == 'vidoof') + end + @results[0][:id].should eq 'oof' end end describe '#text' do it "should select a node's text" do @results = xpath { |x| x.descendant(:p).where(x.text == 'Bax') } - @results[0].text.should == 'Bax' - @results[1][:title].should == 'monkey' + @results[0].text.should eq 'Bax' + @results[1][:title].should eq 'monkey' @results = xpath { |x| x.descendant(:div).where(x.descendant(:p).text == 'Bax') } - @results[0][:title].should == 'fooDiv' + @results[0][:title].should eq 'fooDiv' + end + end + + describe '#substring' do + context 'when called with one argument' do + it 'should select the part of a string after the specified character' do + @results = xpath { |x| x.descendant(:span).where(x.attr(:id) == 'substring').text.substring(7) } + @results.should eq 'there' + end + end + + context 'when called with two arguments' do + it 'should select the part of a string after the specified character, up to the given length' do + @results = xpath { |x| x.descendant(:span).where(x.attr(:id) == 'substring').text.substring(2, 4) } + @results.should eq 'ello' + end + end + end + + describe '#function' do + it 'should call the given xpath function' do + @results = xpath { |x| x.function(:boolean, x.function(:true) == x.function(:false)) } + @results.should eq false + end + end + + describe '#method' do + it 'should call the given xpath function with the current node as the first argument' do + @results = xpath { |x| x.descendant(:span).where(x.attr(:id) == 'string-length').text.method(:"string-length") } + @results.should eq 11 + end + end + + describe '#string_length' do + it 'should return the length of a string' do + @results = xpath { |x| x.descendant(:span).where(x.attr(:id) == 'string-length').text.string_length } + @results.should eq 11 end end describe '#where' do - it "should limit the expression to find only certain nodes" do - xpath { |x| x.descendant(:div).where(:"@id = 'foo'") }.first[:title].should == "fooDiv" + it 'should limit the expression to find only certain nodes' do + xpath { |x| x.descendant(:div).where(:"@id = 'foo'") }.first[:title].should eq 'fooDiv' end - it "should be aliased as []" do - xpath { |x| x.descendant(:div)[:"@id = 'foo'"] }.first[:title].should == "fooDiv" + it 'should be aliased as []' do + xpath { |x| x.descendant(:div)[:"@id = 'foo'"] }.first[:title].should eq 'fooDiv' + end + + it 'should be a no-op when nil condition is passed' do + XPath.descendant(:div).where(nil).to_s.should eq './/div' end end describe '#inverse' do - it "should invert the expression" do - xpath { |x| x.descendant(:p).where(x.attr(:id).equals('fooDiv').inverse) }.first.text.should == 'Bax' + it 'should invert the expression' do + xpath { |x| x.descendant(:p).where(x.attr(:id).equals('fooDiv').inverse) }.first.text.should eq 'Bax' end - it "should be aliased as the unary tilde" do - xpath { |x| x.descendant(:p).where(~x.attr(:id).equals('fooDiv')) }.first.text.should == 'Bax' + it 'should be aliased as the unary tilde' do + xpath { |x| x.descendant(:p).where(~x.attr(:id).equals('fooDiv')) }.first.text.should eq 'Bax' + end + + it 'should be aliased as the unary bang' do + xpath { |x| x.descendant(:p).where(!x.attr(:id).equals('fooDiv')) }.first.text.should eq 'Bax' end end describe '#equals' do - it "should limit the expression to find only certain nodes" do - xpath { |x| x.descendant(:div).where(x.attr(:id).equals('foo')) }.first[:title].should == "fooDiv" + it 'should limit the expression to find only certain nodes' do + xpath { |x| x.descendant(:div).where(x.attr(:id).equals('foo')) }.first[:title].should eq 'fooDiv' + end + + it 'should be aliased as ==' do + xpath { |x| x.descendant(:div).where(x.attr(:id) == 'foo') }.first[:title].should eq 'fooDiv' + end + end + + describe '#not_equals' do + it 'should match only when not equal' do + xpath { |x| x.descendant(:div).where(x.attr(:id).not_equals('bar')) }.first[:title].should eq 'fooDiv' end - it "should be aliased as ==" do - xpath { |x| x.descendant(:div).where(x.attr(:id) == 'foo') }.first[:title].should == "fooDiv" + it 'should be aliased as !=' do + xpath { |x| x.descendant(:div).where(x.attr(:id) != 'bar') }.first[:title].should eq 'fooDiv' end end describe '#is' do - it "uses equality when :exact given" do - xpath(:exact) { |x| x.descendant(:div).where(x.attr(:id).is('foo')) }.first[:title].should == "fooDiv" + it 'uses equality when :exact given' do + xpath(:exact) { |x| x.descendant(:div).where(x.attr(:id).is('foo')) }.first[:title].should eq 'fooDiv' xpath(:exact) { |x| x.descendant(:div).where(x.attr(:id).is('oo')) }.first.should be_nil end - it "uses substring matching otherwise" do - xpath { |x| x.descendant(:div).where(x.attr(:id).is('foo')) }.first[:title].should == "fooDiv" - xpath { |x| x.descendant(:div).where(x.attr(:id).is('oo')) }.first[:title].should == "fooDiv" + it 'uses substring matching otherwise' do + xpath { |x| x.descendant(:div).where(x.attr(:id).is('foo')) }.first[:title].should eq 'fooDiv' + xpath { |x| x.descendant(:div).where(x.attr(:id).is('oo')) }.first[:title].should eq 'fooDiv' end end describe '#one_of' do - it "should return all nodes where the condition matches" do + it 'should return all nodes where the condition matches' do @results = xpath do |x| p = x.anywhere(:div).where(x.attr(:id) == 'foo').attr(:title) x.descendant(:*).where(x.attr(:id).one_of('foo', p, 'baz')) end - @results[0][:title].should == "fooDiv" - @results[1].text.should == "Blah" - @results[2][:title].should == "bazDiv" + @results[0][:title].should eq 'fooDiv' + @results[1].text.should eq 'Blah' + @results[2][:title].should eq 'bazDiv' end end describe '#and' do - it "should find all nodes in both expression" do + it 'should find all nodes in both expression' do @results = xpath do |x| x.descendant(:*).where(x.contains('Bax').and(x.attr(:title).equals('monkey'))) end - @results[0][:title].should == "monkey" + @results[0][:title].should eq 'monkey' end - it "should be aliased as ampersand (&)" do + it 'should be aliased as ampersand (&)' do @results = xpath do |x| x.descendant(:*).where(x.contains('Bax') & x.attr(:title).equals('monkey')) end - @results[0][:title].should == "monkey" + @results[0][:title].should eq 'monkey' end end describe '#or' do - it "should find all nodes in either expression" do + it 'should find all nodes in either expression' do @results = xpath do |x| x.descendant(:*).where(x.attr(:id).equals('foo').or(x.attr(:id).equals('fooDiv'))) end - @results[0][:title].should == "fooDiv" - @results[1].text.should == "Blah" + @results[0][:title].should eq 'fooDiv' + @results[1].text.should eq 'Blah' end - it "should be aliased as pipe (|)" do + it 'should be aliased as pipe (|)' do @results = xpath do |x| x.descendant(:*).where(x.attr(:id).equals('foo') | x.attr(:id).equals('fooDiv')) end - @results[0][:title].should == "fooDiv" - @results[1].text.should == "Blah" + @results[0][:title].should eq 'fooDiv' + @results[1].text.should eq 'Blah' end end describe '#attr' do - it "should be an attribute" do + it 'should be an attribute' do @results = xpath { |x| x.descendant(:div).where(x.attr(:id)) } - @results[0][:title].should == "barDiv" - @results[1][:title].should == "fooDiv" + @results[0][:title].should eq 'barDiv' + @results[1][:title].should eq 'fooDiv' end end describe '#css' do - it "should find nodes by the given CSS selector" do + it 'should find nodes by the given CSS selector' do @results = xpath { |x| x.css('#preference p') } - @results[0].text.should == 'allamas' - @results[1].text.should == 'llama' + @results[0].text.should eq 'allamas' + @results[1].text.should eq 'llama' end - it "should respect previous expression" do + it 'should respect previous expression' do @results = xpath { |x| x.descendant[x.attr(:id) == 'moar'].css('p') } - @results[0].text.should == 'chimp' - @results[1].text.should == 'flamingo' + @results[0].text.should eq 'chimp' + @results[1].text.should eq 'flamingo' end - it "should be composable" do + it 'should be composable' do @results = xpath { |x| x.css('#moar').descendant(:p) } - @results[0].text.should == 'chimp' - @results[1].text.should == 'flamingo' + @results[0].text.should eq 'chimp' + @results[1].text.should eq 'flamingo' end - it "should allow comma separated selectors" do + it 'should allow comma separated selectors' do @results = xpath { |x| x.descendant[x.attr(:id) == 'moar'].css('div, p') } - @results[0].text.should == 'chimp' - @results[1].text.should == 'elephant' - @results[2].text.should == 'flamingo' + @results[0].text.should eq 'chimp' + @results[1].text.should eq 'elephant' + @results[2].text.should eq 'flamingo' end end - describe '#name' do + describe '#qname' do it "should match the node's name" do - xpath { |x| x.descendant(:*).where(x.name == 'ul') }.first.text.should == "A list" + xpath { |x| x.descendant(:*).where(x.qname == 'ul') }.first.text.should eq 'A list' end end describe '#union' do - it "should create a union expression" do + it 'should create a union expression' do @expr1 = XPath.generate { |x| x.descendant(:p) } @expr2 = XPath.generate { |x| x.descendant(:div) } @collection = @expr1.union(@expr2) @xpath1 = @collection.where(XPath.attr(:id) == 'foo').to_xpath @xpath2 = @collection.where(XPath.attr(:id) == 'fooDiv').to_xpath @results = doc.xpath(@xpath1) - @results[0][:title].should == 'fooDiv' + @results[0][:title].should eq 'fooDiv' @results = doc.xpath(@xpath2) - @results[0][:id].should == 'fooDiv' + @results[0][:id].should eq 'fooDiv' end - it "should be aliased as +" do + it 'should be aliased as +' do @expr1 = XPath.generate { |x| x.descendant(:p) } @expr2 = XPath.generate { |x| x.descendant(:div) } @collection = @expr1 + @expr2 @xpath1 = @collection.where(XPath.attr(:id) == 'foo').to_xpath @xpath2 = @collection.where(XPath.attr(:id) == 'fooDiv').to_xpath @results = doc.xpath(@xpath1) - @results[0][:title].should == 'fooDiv' + @results[0][:title].should eq 'fooDiv' @results = doc.xpath(@xpath2) - @results[0][:id].should == 'fooDiv' + @results[0][:id].should eq 'fooDiv' + end + end + + describe '#last' do + it 'returns the number of elements in the context' do + @results = xpath { |x| x.descendant(:p)[XPath.position() == XPath.last()] } + @results[0].text.should eq 'Bax' + @results[1].text.should eq 'Blah' + @results[2].text.should eq 'llama' + end + end + + describe '#position' do + it 'returns the position of elements in the context' do + @results = xpath { |x| x.descendant(:p)[XPath.position() == 2] } + @results[0].text.should eq 'Bax' + @results[1].text.should eq 'Bax' + end + end + + describe '#count' do + it 'counts the number of occurrences' do + @results = xpath { |x| x.descendant(:div)[x.descendant(:p).count == 2] } + @results[0][:id].should eq 'preference' + end + end + + describe '#lte' do + it 'checks lesser than or equal' do + @results = xpath { |x| x.descendant(:p)[XPath.position() <= 2] } + @results[0].text.should eq 'Blah' + @results[1].text.should eq 'Bax' + @results[2][:title].should eq 'gorilla' + @results[3].text.should eq 'Bax' + end + end + + describe '#lt' do + it 'checks lesser than' do + @results = xpath { |x| x.descendant(:p)[XPath.position() < 2] } + @results[0].text.should eq 'Blah' + @results[1][:title].should eq 'gorilla' + end + end + + describe '#gte' do + it 'checks greater than or equal' do + @results = xpath { |x| x.descendant(:p)[XPath.position() >= 2] } + @results[0].text.should eq 'Bax' + @results[1][:title].should eq 'monkey' + @results[2].text.should eq 'Bax' + @results[3].text.should eq 'Blah' + end + end + + describe '#gt' do + it 'checks greater than' do + @results = xpath { |x| x.descendant(:p)[XPath.position() > 2] } + @results[0][:title].should eq 'monkey' + @results[1].text.should eq 'Blah' + end + end + + describe '#plus' do + it 'adds stuff' do + @results = xpath { |x| x.descendant(:p)[XPath.position().plus(1) == 2] } + @results[0][:id].should eq 'fooDiv' + @results[1][:title].should eq 'gorilla' + end + end + + describe '#minus' do + it 'subtracts stuff' do + @results = xpath { |x| x.descendant(:p)[XPath.position().minus(1) == 0] } + @results[0][:id].should eq 'fooDiv' + @results[1][:title].should eq 'gorilla' end end + describe '#multiply' do + it 'multiplies stuff' do + @results = xpath { |x| x.descendant(:p)[XPath.position() * 3 == 3] } + @results[0][:id].should eq 'fooDiv' + @results[1][:title].should eq 'gorilla' + end + end + + describe '#divide' do + it 'divides stuff' do + @results = xpath { |x| x.descendant(:p)[XPath.position() / 2 == 1] } + @results[0].text.should eq 'Bax' + @results[1].text.should eq 'Bax' + end + end + + describe '#mod' do + it 'take modulo' do + @results = xpath { |x| x.descendant(:p)[XPath.position() % 2 == 1] } + @results[0].text.should eq 'Blah' + @results[1][:title].should eq 'monkey' + @results[2][:title].should eq 'gorilla' + end + end + + describe '#ancestor' do + it 'finds ancestor nodes' do + @results = xpath { |x| x.descendant(:p)[1].ancestor } + @results[0].node_name.should eq 'html' + @results[1].node_name.should eq 'body' + @results[2][:id].should eq 'foo' + end + end end diff -Nru ruby-xpath-2.0.0/xpath.gemspec ruby-xpath-3.2.0/xpath.gemspec --- ruby-xpath-2.0.0/xpath.gemspec 1970-01-01 00:00:00.000000000 +0000 +++ ruby-xpath-3.2.0/xpath.gemspec 2019-01-05 15:00:16.000000000 +0000 @@ -0,0 +1,48 @@ +######################################################### +# This file has been automatically generated by gem2tgz # +######################################################### +# -*- encoding: utf-8 -*- +# stub: xpath 3.2.0 ruby lib + +Gem::Specification.new do |s| + s.name = "xpath".freeze + s.version = "3.2.0" + + s.required_rubygems_version = Gem::Requirement.new(">= 0".freeze) if s.respond_to? :required_rubygems_version= + s.require_paths = ["lib".freeze] + s.authors = ["Jonas Nicklas".freeze] + s.cert_chain = ["gem-public_cert.pem".freeze] + s.date = "2018-10-15" + s.description = "XPath is a Ruby DSL for generating XPath expressions".freeze + s.email = ["jonas.nicklas@gmail.com".freeze] + s.files = ["README.md".freeze, "lib/xpath.rb".freeze, "lib/xpath/dsl.rb".freeze, "lib/xpath/expression.rb".freeze, "lib/xpath/literal.rb".freeze, "lib/xpath/renderer.rb".freeze, "lib/xpath/union.rb".freeze, "lib/xpath/version.rb".freeze, "spec/fixtures/form.html".freeze, "spec/fixtures/simple.html".freeze, "spec/fixtures/stuff.html".freeze, "spec/spec_helper.rb".freeze, "spec/union_spec.rb".freeze, "spec/xpath_spec.rb".freeze] + s.homepage = "https://github.com/teamcapybara/xpath".freeze + s.licenses = ["MIT".freeze] + s.required_ruby_version = Gem::Requirement.new(">= 2.3".freeze) + s.rubygems_version = "2.5.2.1".freeze + s.summary = "Generate XPath expressions from Ruby".freeze + + if s.respond_to? :specification_version then + s.specification_version = 4 + + if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then + s.add_runtime_dependency(%q.freeze, ["~> 1.8"]) + s.add_development_dependency(%q.freeze, [">= 0"]) + s.add_development_dependency(%q.freeze, [">= 0"]) + s.add_development_dependency(%q.freeze, ["~> 3.0"]) + s.add_development_dependency(%q.freeze, [">= 0.5.8"]) + else + s.add_dependency(%q.freeze, ["~> 1.8"]) + s.add_dependency(%q.freeze, [">= 0"]) + s.add_dependency(%q.freeze, [">= 0"]) + s.add_dependency(%q.freeze, ["~> 3.0"]) + s.add_dependency(%q.freeze, [">= 0.5.8"]) + end + else + s.add_dependency(%q.freeze, ["~> 1.8"]) + s.add_dependency(%q.freeze, [">= 0"]) + s.add_dependency(%q.freeze, [">= 0"]) + s.add_dependency(%q.freeze, ["~> 3.0"]) + s.add_dependency(%q.freeze, [">= 0.5.8"]) + end +end