ruby_rnv 0.3.0 → 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/ext/rnv/src/xsd.h CHANGED
@@ -14,10 +14,9 @@
14
14
  #define XSD_ER_WS 5
15
15
  #define XSD_ER_ENUM 6
16
16
 
17
- extern void xsd_default_verror_handler(rnv_t *rnv, int erno,va_list ap);
17
+ extern void xsd_default_verror_handler(void *data, int erno, int (*handler)(void *data, int erno,char *format, va_list ap), va_list ap);
18
18
 
19
19
  extern void xsd_init(rx_st_t *rx_st);
20
- extern void xsd_clear(void);
21
20
 
22
21
  extern int xsd_allows(rx_st_t *rx_st, char *typ,char *ps,char *s,int n);
23
22
  extern int xsd_equal(rx_st_t *rx_st, char *typ,char *val,char *s,int n);
@@ -2,21 +2,19 @@ module RNV
2
2
  # Datatype library callback object
3
3
  # @see https://www.oasis-open.org/committees/relax-ng/spec-20010811.html#IDA1I1R
4
4
  class DataTypeLibrary
5
- # @param [String] typ
5
+ # @param [String] typ the data type
6
6
  # @param [String] val
7
7
  # @param [String] s
8
- # @param [Integer] n
9
8
  # @return [Boolean]
10
- def equal(typ, val, s, n)
9
+ def equal(typ, val, s)
11
10
  true
12
11
  end
13
12
 
14
- # @param [String] typ
13
+ # @param [String] typ the data type
15
14
  # @param [String] ps
16
- # @param [String] s
17
- # @param [Integer] n
15
+ # @param [String] s the value
18
16
  # @return [Boolean]
19
- def allows(typ, ps, s, n)
17
+ def allows(typ, ps, s)
20
18
  true
21
19
  end
22
20
  end
data/lib/rnv/error.rb CHANGED
@@ -1,13 +1,113 @@
1
1
  module RNV
2
2
  class Error
3
+ attr_reader :original_message, :original_expected
4
+ attr_reader :ns_uri, :element, :attr, :value
5
+ attr_reader :xpath
6
+
7
+ # @return [String]
8
+ def message
9
+ @original_message
10
+ end
11
+
12
+ # @return [String]
13
+ def expected
14
+ @original_expected
15
+ end
16
+
17
+ # @return [String]
18
+ def compact_message
19
+ case @code
20
+ when :rnv_er_elem
21
+ "element <#{@element}> is not allowed"
22
+ when :rnv_er_ufin
23
+ "element <#{@element}> is incomplete"
24
+ when :rnv_er_akey
25
+ "attribute #{@attr} is not allowed"
26
+ when :rnv_er_aval
27
+ "attribute #{@attr} has invalid value '#{@value}'"
28
+ when :rnv_er_amis
29
+ "element <#{@element}> attribute missing"
30
+ else
31
+ @original_message
32
+ end
33
+ end
34
+
35
+ # @return [String]
36
+ def compact_expected
37
+ [(compact_required_set.length > 0 ? compact_expected_phrase(compact_required_set) + " required" : nil),
38
+ (compact_allowed_set.length > 0 ? compact_expected_phrase(compact_allowed_set) + " allowed" : nil)].join("; ")
39
+ end
40
+
41
+ # @param [String] data original content
42
+ # @return [String] context
43
+ def contextualize(data, max_len = 60)
44
+ out = ""
45
+ if data and @line
46
+ err_data = data.split("\n")[@line - 1]
47
+ if err_data && err_data.length > @col - 1
48
+ err_data.insert(@col - 1, "🢑")
49
+
50
+ start = 0
51
+ if @col > max_len
52
+ start = @col - max_len
53
+ end
54
+ out += (start > 0 ? "…" : "") + err_data[start..(@col + max_len)].strip + (@col + max_len < err_data.length ? "…" : "")
55
+ end
56
+ end
57
+ out
58
+ end
59
+
3
60
  # @return [String]
4
61
  def to_s
5
- "#{@line}:#{@col}:error: #{@message}\n#{@expected}"
62
+ "#{@line}:#{@col}:error: #{self.message}\n#{self.expected}"
6
63
  end
7
64
 
8
65
  # @return [String]
9
66
  def inspect
10
- "#<RNV::Error code: :#{@code}, message: '#{@message}', expected: '#{@expected} line: #{@line}, column: #{@col}>"
67
+ "#<RNV::Error code: :#{@code}, message: '#{self.message}', expected: '#{self.expected}, line: #{@line}, column: #{@col}>"
68
+ end
69
+
70
+ def required
71
+ @required.select{|a| @attr ? a.first == :rn_p_attribute : true}
72
+ end
73
+
74
+ def allowed
75
+ @allowed.select{|a| @attr ? a.first == :rn_p_attribute : true}
76
+ end
77
+
78
+ private
79
+
80
+ def compact_expected_to_s(e, with_ns = false)
81
+ case e.first
82
+ when :rn_p_attribute
83
+ compact_expected_to_s(e.last, with_ns)
84
+ when :rn_p_element
85
+ "<" + compact_expected_to_s(e.last, with_ns) + ">"
86
+ when :rn_p_data
87
+ compact_expected_to_s(e.last, with_ns)
88
+ when :rn_p_value
89
+ "\"#{e.last}\""
90
+ when :rn_nc_datatype
91
+ "datatype #{e[-2]}:#{e.last}"
92
+ when :rn_nc_qname
93
+ with_ns ? "#{e.first}:#{e.last}" : e.last
94
+ end
95
+ end
96
+
97
+ def compact_required_set
98
+ @compact_required_set ||= required.map { |r| compact_expected_to_s(r) }.compact.uniq
99
+ end
100
+
101
+ def compact_allowed_set
102
+ @compact_allowed_set ||= allowed.map { |r| compact_expected_to_s(r) }.compact.uniq
103
+ end
104
+
105
+ def compact_expected_phrase(set)
106
+ if set.length > 1
107
+ set[0..-2].join(", ") + " or " + set.last
108
+ else
109
+ set.last
110
+ end
11
111
  end
12
112
  end
13
- end
113
+ end
data/lib/rnv/validator.rb CHANGED
@@ -3,36 +3,98 @@ require 'rnv/rnv'
3
3
  require 'rnv/pre_processor'
4
4
 
5
5
  module RNV
6
+ class DocumentEmpty < StandardError; end
7
+
8
+ # @!visibility private
9
+ class XpathNode
10
+ attr_accessor :name
11
+ attr_accessor :uri, :namespaces
12
+ attr_accessor :parent
13
+ attr_accessor :children
14
+
15
+ def initialize(name)
16
+ @name = name
17
+ @children = []
18
+ end
19
+
20
+ def add_child(name, uri = nil, namespaces = {})
21
+ child = XpathNode.new(name)
22
+ child.uri = uri
23
+ child.namespaces = namespaces
24
+ child.parent = self
25
+ @children << child
26
+ child
27
+ end
28
+
29
+ def to_xpath
30
+ xpath = []
31
+ current = self
32
+ namespaces = {}
33
+ rev_namespaces = {}
34
+ ns_current = self
35
+ while ns_current.name
36
+ ns_current.namespaces.each do |prefix, uri|
37
+ rev_namespaces[uri] ||= []
38
+ rev_namespaces[uri] << prefix
39
+ end
40
+ ns_current = ns_current.parent
41
+ end
42
+
43
+ rev_namespaces.each do |uri, prefixes|
44
+ if prefixes.length > 0
45
+ prefixes.select! { |prefix| prefix != "xmlns" }
46
+ end
47
+ namespaces[prefixes.first||"xmlns"] = uri
48
+ end
49
+
50
+ while current.name
51
+ xpath << "#{rev_namespaces[current.uri].first||"xmlns"}:#{current.name}[#{current.parent.children.select { |child| child.name == current.name }.index(current) + 1}]"
52
+ current = current.parent
53
+ end
54
+ [xpath.reverse, namespaces]
55
+ end
56
+ end
57
+
6
58
  # @!visibility private
7
59
  class NokogiriSaxDocument < Nokogiri::XML::SAX::Document
8
60
  # @return [Nokogiri::XML::SAX::ParserContext]
9
- attr_accessor :ctx, :pre_processor
61
+ attr_accessor :ctx
62
+ attr_accessor :pre_processor
63
+
10
64
  # @param [RNV::Document] document
11
65
  def initialize(document)
12
66
  @document = document
67
+ @xpath_tree = XpathNode.new(nil)
13
68
  end
14
69
 
15
70
  def start_element_namespace(name, attrs = [], prefix = nil, uri = nil, ns = nil)
16
- update_line_col
17
71
  tag_attrs = attrs.map { |attr| [attr.uri ? "#{attr.uri}:#{attr.localname}" : attr.localname, attr.value] }
18
72
  tag_name = uri ? "#{uri}:#{name}" : name
73
+ namespaces = {}
74
+ ns.each do |n|
75
+ namespaces[n.first || "xmlns"] = n.last
76
+ end
77
+ @xpath_tree = @xpath_tree.add_child(name, uri, namespaces)
78
+
79
+ update_line_col
19
80
  @document.start_tag(@pre_processor.tag(tag_name), @pre_processor.attributes(tag_attrs))
20
81
  end
21
82
 
22
83
  def end_element_namespace(name, prefix = nil, uri = nil)
23
- update_line_col
84
+ @xpath_tree = @xpath_tree.parent
24
85
  tag_name = uri ? "#{uri}:#{name}" : name
86
+ update_line_col
25
87
  @document.end_tag(@pre_processor.tag(tag_name))
26
88
  end
27
89
 
28
- def characters str
90
+ def characters(value)
29
91
  update_line_col
30
- @document.characters(@pre_processor.text(str))
92
+ @document.characters(@pre_processor.text(value))
31
93
  end
32
94
 
33
- def cdata_block str
95
+ def cdata_block(value)
34
96
  update_line_col
35
- @document.characters(@pre_processor.(str))
97
+ @document.characters(@pre_processor.text(value))
36
98
  end
37
99
 
38
100
  private
@@ -40,6 +102,8 @@ module RNV
40
102
  def update_line_col
41
103
  @document.last_line = @ctx.line
42
104
  @document.last_col = @ctx.column
105
+ xpath = @xpath_tree.to_xpath
106
+ @document.xpath = ["/" + xpath.first.join("/"), xpath.last]
43
107
  end
44
108
  end
45
109
 
@@ -78,6 +142,8 @@ module RNV
78
142
  rnv_doc = NokogiriSaxDocument.new(@document)
79
143
  rnv_doc.pre_processor = pre_processor
80
144
 
145
+ raise RNV::DocumentEmpty if str.nil? or str.empty?
146
+
81
147
  parser = Nokogiri::XML::SAX::Parser.new(rnv_doc)
82
148
  parser.parse_memory(str) do |ctx|
83
149
  ctx.replace_entities = true
@@ -98,6 +164,8 @@ module RNV
98
164
 
99
165
  file = xml.is_a?(File) ? xml : File.open(xml)
100
166
 
167
+ raise RNV::DocumentEmpty if file.size == 0
168
+
101
169
  parser = Nokogiri::XML::SAX::Parser.new(rnv_doc)
102
170
  parser.parse(file) do |ctx|
103
171
  ctx.replace_entities = true
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ruby_rnv
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.0
4
+ version: 0.5.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Julien Boulnois
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2021-04-09 00:00:00.000000000 Z
11
+ date: 2021-07-11 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -104,6 +104,8 @@ files:
104
104
  - Gemfile
105
105
  - ext/rnv/extconf.rb
106
106
  - ext/rnv/ruby_rnv.c
107
+ - ext/rnv/ruby_rnv.h
108
+ - ext/rnv/ruby_rnv_err.c
107
109
  - ext/rnv/src/ary.c
108
110
  - ext/rnv/src/ary.h
109
111
  - ext/rnv/src/drv.c