lib/jini.rb in jini-1.1.5 vs lib/jini.rb in jini-1.2.5

- old
+ new

@@ -1,7 +1,5 @@ -# frozen_string_literal: true - # (The MIT License) # # Copyright (c) 2022 Ivanchuk Ivan # # Permission is hereby granted, free of charge, to any person obtaining a copy @@ -38,10 +36,13 @@ # => 'parent/child[@toy="plane"] class Jini # When path not valid class InvalidPath < StandardError; end + # When method not found + class UnsupportedOperation < StandardError; end + # Makes new object. # By default it creates an empty path and you can ignore the head parameter. # @param head [String] # @since 0.0.1 def initialize(head = '') @@ -56,10 +57,72 @@ copy = @head.split(%r{//|/}) copy.each(&method(:space_check)) @head.to_s end + class << self + # From. + # Creates new Jini object from XPATH. + # + # @param [String] xpath + # @raise [InvalidPath] when XPATH is invalid + # @return [Jini] object + def from(xpath) + raise InvalidPath, 'XPATH isn\'t valid' unless xpath_match?(xpath) + Jini.new(xpath) + end + + private + + # This regex matches general case of XPATH. + # @param xpath [String] + # @return [Boolean] matching regex + def xpath_match?(xpath) + xpath.match?(xpath_regex) + end + + def prefix_regex + %r{^/?} + end + + def tag_regex + /([a-zA-Z0-9]+:)?[a-zA-Z0-9]+/ + end + + def bracket_regex + /(\[[^\[\]]*\])/ + end + + def attr_regex + /@\w+=[^\]]+/ + end + + def or_regex + /(\|)/ + end + + def namespace_regex + /([a-zA-Z0-9]+:)?[a-zA-Z0-9]+/ + end + + def sub_xpath_regex + /#{namespace_regex}#{bracket_regex}*(#{attr_regex})*/ + end + + def or_sub_xpath_regex + /#{or_regex}#{namespace_regex}#{bracket_regex}*(#{attr_regex})*/ + end + + def xpath_regex + %r{\A#{prefix_regex}#{namespace_regex}(/#{sub_xpath_regex})*#{or_sub_xpath_regex}*(/#{sub_xpath_regex})*\Z} + end + end + + def ==(other) + self.class == other.class && to_s == other.to_s + end + # Additional node for xpath. # @param node [String] the node # @return [Jini] object with additional node # @since 0.0.1 def add_node(node) @@ -235,11 +298,11 @@ raise InvalidPath, 'Invalid path, empty node' if node.length.eql? 0 end # @param node [String] node for check def space_check(node) - raise InvalidPath, "Nodes can't contain spaces: #{node} – contain space." if valid? node + raise InvalidPath, "Nodes can't contain spaces: #{node} – contain space." if valid_node? node end # Regex: '[' or ']' or '@' or '//'. # @param node [String] # @return [Boolean] matching regex @@ -248,11 +311,11 @@ end # Regex: '[' or ']' or '@' or '=' or '<' or '>'. # @param node [String] node for check # @return [Boolean] matching regex - def valid?(node) + def valid_node?(node) !node.match(/[|]|@|=|>|</) && node.include?(' ') end # Some action between two statements. def action_between(action, alpha, beta) @@ -261,7 +324,15 @@ # Purging head from token. # @param [Regexp | String] token to be purged from the head def purge_head(token) @head.gsub(token, '') + end + + def method_missing(method_name, *_args) + raise UnsupportedOperation, "The method #{method_name} was not found!" + end + + def respond_to_missing?(_method_name, _include_private = false) + true end end