ruby-jing 0.0.2 → 0.1.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.
Files changed (5) hide show
  1. checksums.yaml +5 -5
  2. data/README.rdoc +4 -4
  3. data/lib/jing.rb +28 -13
  4. data/test/test_jing.rb +49 -18
  5. metadata +22 -8
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: 19b9643f4db8f71aa3ef7df70166632203585784
4
- data.tar.gz: 7df428f044ebfae4cffcf95f0cf1adca60227782
2
+ SHA256:
3
+ metadata.gz: 41284b05a5ee61d28bbf52115ad2c910ee85791edf63880786ac413f9d190b71
4
+ data.tar.gz: e373a5ca42a69b3f6bd7a663155239904cc0f2fd8fd2033ebd19f8586ac2490a
5
5
  SHA512:
6
- metadata.gz: be774aaf821cd382797c28b93146db7da50b114fc357c86bfefbd6e46a4d825f97c27ea88184634b4d08970a84af337852b1e697c95cdc73bce4b4d048b67c39
7
- data.tar.gz: f49cdcd0d6fa805f8530a8d2f531619885afbcdd3c614e4cd876c61f1e9906d9ff5ef9e929a407bff568ef886e5f79605b6ddfa681ca517badd456e777935c1a
6
+ metadata.gz: 858919ea520690526014c81aeba7f77308933dbd4afcc52fe2a1e40d8a5f1d8f1267b2dd133c5617cdd60cec8f7934595d03fab0ac087c6fdadbb9203a91cddb
7
+ data.tar.gz: 94c9479f1a222b58b81d150806c3d937913436cdb4c2c35d29892ce06be0d7f405400ff8284cbddc9c1caa443ac38e76ab3f0706a65e435863b3b8d98efa57d7
data/README.rdoc CHANGED
@@ -1,6 +1,6 @@
1
1
  = Ruby Jing
2
2
 
3
- {<img src="https://secure.travis-ci.org/sshaw/ruby-jing.png"/>}[http://travis-ci.org/sshaw/ruby-jing]
3
+ {<img src="https://github.com/sshaw/ruby-jing/actions/workflows/rake.yml/badge.svg"/>}[https://github.com/sshaw/ruby-jing/actions/workflows/rake.yml]
4
4
  {<img src="https://codeclimate.com/github/sshaw/ruby-jing.png" />}[https://codeclimate.com/github/sshaw/ruby-jing]
5
5
 
6
6
  RELAX NG schema validation using the {Jing CLI}[http://www.thaiopensource.com/relaxng/jing.html]
@@ -55,7 +55,7 @@ Simple: good error messages. Let's look at the error messages provided by each o
55
55
 
56
56
  <!-- XML B -->
57
57
  <addressBook>
58
- <card verison="v100">
58
+ <card verison="v100">
59
59
  <name>John Smith</name>
60
60
  <oops>Doh!</oops>
61
61
  </card>
@@ -65,7 +65,7 @@ Simple: good error messages. Let's look at the error messages provided by each o
65
65
 
66
66
  schema = Nokogiri::XML::RelaxNG(File.read(rng))
67
67
  doc = Nokogiri::XML(File.read(xml))
68
- errors = schema.validate(doc)
68
+ errors = schema.validate(doc)
69
69
  errors.each { |e| puts e }
70
70
 
71
71
  Resulting errors:
@@ -87,7 +87,7 @@ Resulting errors:
87
87
 
88
88
  Fails for XML A and XML B --it treats the XML declaration as a validation error!
89
89
 
90
- Validation error. Expected: :start_element( addressBook ) from < S.1 #:start_element( addressBook ), < Z.2 #:start_element( card ), :start_attribute( version ), < C.3 :text( v1 ) or :text( v2 ) >, :end_attribute( ), :start_element( name ), :text( ), :end_element( ), :start_element( email ), :text( ), :end_element( ), :end_element( ) >, :end_element( ), :end_document( ) > but got <?xml ... ?>(
90
+ Validation error. Expected: :start_element( addressBook ) from < S.1 #:start_element( addressBook ), < Z.2 #:start_element( card ), :start_attribute( version ), < C.3 :text( v1 ) or :text( v2 ) >, :end_attribute( ), :start_element( name ), :text( ), :end_element( ), :start_element( email ), :text( ), :end_element( ), :end_element( ) >, :end_element( ), :end_document( ) > but got <?xml ... ?>(
91
91
  )
92
92
 
93
93
  ==== Jing
data/lib/jing.rb CHANGED
@@ -1,7 +1,8 @@
1
+ require "open3"
1
2
  require "optout"
2
3
 
3
4
  class Jing
4
- VERSION = "0.0.2"
5
+ VERSION = "0.1.0"
5
6
  DEFAULT_JAR = File.join(File.dirname(__FILE__), "jing-20091111.jar")
6
7
 
7
8
  Error = Class.new(StandardError)
@@ -32,6 +33,7 @@ class Jing
32
33
  # === Options
33
34
  #
34
35
  # [:java (String)] Name and/or location of the java executable. Defaults to <code>"java"</code>.
36
+ # [:java_opts (String)] JVM options passed to +java+, e.g. +"-Dfile.encoding=UTF-8"+. Use this to set +"-D"+ system properties (e.g. +jdk.xml.maxGeneralEntitySizeLimit+) instead of the +JAVA_TOOL_OPTIONS+/_JAVA_OPTIONS+ environment variables, which make the JVM print a +Picked up ...+ banner to stderr on every launch.
35
37
  # [:jar (String)] Path to the Jing JAR file. Defaults to the bundled JAR.
36
38
  # [:compact (Boolean)] Set to +true+ if the schema uses the RELAX NG compact syntax. Defaults to false, will be set to +true+ is the schema has a +.rnc+ extension.
37
39
  # [:encoding (String)] Encoding of the XML document.
@@ -53,7 +55,8 @@ class Jing
53
55
  # Optout quirk: true will *include* the switch, which means we *don't* want to check
54
56
  @options[:id_check] = !@options[:id_check] if @options.include?(:id_check)
55
57
  if @options[:encoding]
56
- @options[:java_opts] = "-Dfile.encoding=#{@options[:encoding]}"
58
+ file_encoding = "-Dfile.encoding=#{@options[:encoding]}"
59
+ @options[:java_opts] = [@options[:java_opts], file_encoding].compact.join(" ")
57
60
  end
58
61
  end
59
62
 
@@ -87,11 +90,10 @@ class Jing
87
90
  def validate(xml)
88
91
  @options[:xmlfile] = xml
89
92
 
90
- out = execute(@options)
91
- return [] if $?.success? and out.empty?
92
- errors = parse_output(out)
93
- raise ExecutionError, out if errors.none? # There must have been a problem that was not schema related
94
- errors
93
+ out, status = execute(@options)
94
+ return [] if status.success? and out.empty?
95
+
96
+ parse_output(out)
95
97
  end
96
98
 
97
99
  # Validate an XML document against the schema. To receive a list of validation errors use #validate.
@@ -107,19 +109,26 @@ class Jing
107
109
  # Same as #validate
108
110
  #
109
111
  # === Returns
110
- #
112
+ #
111
113
  # [Boolean] +true+ if valid, +false+ if invalid
112
114
  #
113
-
115
+
114
116
  def valid?(xml)
115
117
  errors = validate(xml)
116
118
  errors.none?
117
119
  end
118
-
120
+
119
121
  private
122
+ # Spawn java directly in argv form instead of shelling out via backticks.
123
+ # A shell-form spawn needs /bin/sh, which is not always reachable from the
124
+ # calling process (restricted containers, TruffleRuby processes with a
125
+ # virtual filesystem mounted at /, ...); direct exec needs no shell. It
126
+ # also removes the shell-injection surface of interpolating paths into a
127
+ # command string. Behavior is unchanged: stderr is merged into the
128
+ # captured output and the exit status is returned alongside it.
120
129
  def execute(options)
121
- cmd = @@option_builder.shell(options)
122
- `#{cmd} 2>&1`
130
+ argv = @@option_builder.argv(options)
131
+ Open3.capture2e(*argv)
123
132
  rescue SystemCallError => e
124
133
  raise ExecutionError, "jing execution failed: #{e}"
125
134
  rescue Optout::OptionError => e
@@ -129,13 +138,19 @@ class Jing
129
138
  def parse_output(output)
130
139
  errors = []
131
140
  output.split("\n").each do |line|
132
- if line =~ /\A(.+):(\d+):(\d+):\s+\w+:\s+(.+)\Z/
141
+ case line
142
+ when /\A(.+):(\d+):(\d+):\s+\w+:\s+(.+)\Z/
133
143
  errors << {
134
144
  :source => $1,
135
145
  :line => $2.to_i,
136
146
  :column => $3.to_i,
137
147
  :message => $4
138
148
  }
149
+ when /Picked up [A-Z_][A-Z0-9_]*: /
150
+ # ignore JVM diagnostic banner printed for env vars like
151
+ # _JAVA_OPTIONS, JAVA_TOOL_OPTIONS and JDK_JAVA_OPTIONS
152
+ else # There must have been a problem that was not schema related
153
+ raise ExecutionError, output
139
154
  end
140
155
  end
141
156
  errors
data/test/test_jing.rb CHANGED
@@ -12,7 +12,7 @@ class TestJing < MiniTest::Unit::TestCase
12
12
 
13
13
  def test_default_jar_file_used
14
14
  cmd = fakeshell { Jing.new(RNG_SCHEMA).validate(VALID_XML) }
15
- assert_match /\A'java'\s+ -jar\s+ '#{Jing::DEFAULT_JAR}' \s+/x, cmd
15
+ assert_match /\Ajava\s+ -jar\s+ #{Regexp.escape(Jing::DEFAULT_JAR)} \s+/x, cmd
16
16
  end
17
17
 
18
18
  def test_jar_file_must_exist
@@ -24,13 +24,13 @@ class TestJing < MiniTest::Unit::TestCase
24
24
  def test_jar_option
25
25
  jar = Tempfile.new "jar"
26
26
  cmd = fakeshell { Jing.new(RNG_SCHEMA, :jar => jar.path).validate(VALID_XML) }
27
- assert_match /\A'java'\s+ -jar\s+ '#{jar.path}' \s+/x, cmd
27
+ assert_match /\Ajava\s+ -jar\s+ #{Regexp.escape(jar.path)} \s+/x, cmd
28
28
  end
29
29
 
30
30
  def test_java_option
31
31
  java = "/usr/alt/java"
32
32
  cmd = fakeshell { Jing.new(RNG_SCHEMA, :java => java).validate(VALID_XML) }
33
- assert_match /\A'#{java}'\s+/, cmd
33
+ assert_match /\A#{Regexp.escape(java)}\s+/, cmd
34
34
  end
35
35
 
36
36
  def test_java_must_exist
@@ -43,12 +43,12 @@ class TestJing < MiniTest::Unit::TestCase
43
43
  def test_encoding_option
44
44
  enc = "iso-8859-1"
45
45
  cmd = fakeshell { Jing.new(RNG_SCHEMA, :encoding => enc).validate(VALID_XML) }
46
- assert_match /\A'java'\s+ '-Dfile.encoding=#{enc}'\s+ -jar\s+ '#{Jing::DEFAULT_JAR}'\s+ -e\s+ '#{enc}'/x, cmd
46
+ assert_match /\Ajava\s+ -Dfile\.encoding=#{enc}\s+ -jar\s+ #{Regexp.escape(Jing::DEFAULT_JAR)}\s+ -e\s+ #{enc}/x, cmd
47
47
  end
48
48
 
49
49
  def test_id_check_option
50
50
  cmd = fakeshell { Jing.new(RNG_SCHEMA, :id_check => false).validate(VALID_XML) }
51
- assert_match /\A'java'\s -jar\s+ '#{Jing::DEFAULT_JAR}'\s+ -i/x, cmd
51
+ assert_match /\Ajava\s -jar\s+ #{Regexp.escape(Jing::DEFAULT_JAR)}\s+ -i/x, cmd
52
52
 
53
53
  cmd = fakeshell { Jing.new(RNG_SCHEMA, :id_check => true).validate(VALID_XML) }
54
54
  refute_match /\b-i\b/x, cmd
@@ -59,7 +59,7 @@ class TestJing < MiniTest::Unit::TestCase
59
59
 
60
60
  def test_compact_option
61
61
  cmd = fakeshell { Jing.new(RNC_SCHEMA, :compact => true).validate(VALID_XML) }
62
- assert_match /\A'java'\s -jar\s+ '#{Jing::DEFAULT_JAR}'\s+ -c/x, cmd
62
+ assert_match /\Ajava\s -jar\s+ #{Regexp.escape(Jing::DEFAULT_JAR)}\s+ -c/x, cmd
63
63
 
64
64
  cmd = fakeshell { Jing.new(RNC_SCHEMA, :compact => false).validate(VALID_XML) }
65
65
  refute_match /\b-c\b/, cmd
@@ -67,7 +67,7 @@ class TestJing < MiniTest::Unit::TestCase
67
67
 
68
68
  def test_compact_option_when_compact_schema_is_used
69
69
  cmd = fakeshell { Jing.new(RNC_SCHEMA).validate(VALID_XML) }
70
- assert_match /\A'java'\s+ -jar\s+ '#{Jing::DEFAULT_JAR}'\s+ -c/x, cmd
70
+ assert_match /\Ajava\s+ -jar\s+ #{Regexp.escape(Jing::DEFAULT_JAR)}\s+ -c/x, cmd
71
71
  end
72
72
 
73
73
  def test_relaxng_file_must_exist
@@ -113,28 +113,59 @@ class TestJing < MiniTest::Unit::TestCase
113
113
  end
114
114
  end
115
115
 
116
+ def test_java_options_env_diagnostic_message
117
+ output = "Picked up _JAVA_OPTIONS: -Djava.io.tmpdir=/tmp"
118
+ fakeshell(:exit => 0, :output => output) {
119
+ errors = Jing.new(RNG_SCHEMA).validate(VALID_XML)
120
+ assert_equal 0, errors.size
121
+ }
122
+ end
123
+
124
+ def test_java_tool_options_env_diagnostic_message
125
+ output = "Picked up JAVA_TOOL_OPTIONS: -Djdk.xml.maxGeneralEntitySizeLimit=200000"
126
+ fakeshell(:exit => 0, :output => output) {
127
+ errors = Jing.new(RNG_SCHEMA).validate(VALID_XML)
128
+ assert_equal 0, errors.size
129
+ }
130
+ end
131
+
132
+ def test_jdk_java_options_env_diagnostic_message
133
+ output = "Picked up JDK_JAVA_OPTIONS: -Dfile.encoding=UTF-8"
134
+ fakeshell(:exit => 0, :output => output) {
135
+ errors = Jing.new(RNG_SCHEMA).validate(VALID_XML)
136
+ assert_equal 0, errors.size
137
+ }
138
+ end
139
+
140
+ def test_java_opts_and_encoding_are_combined
141
+ opts = "-Djdk.xml.maxGeneralEntitySizeLimit=200000"
142
+ cmd = fakeshell { Jing.new(RNG_SCHEMA, :java_opts => opts, :encoding => "iso-8859-1").validate(VALID_XML) }
143
+ assert_match(/#{opts} -Dfile\.encoding=iso-8859-1\s+-jar/, cmd)
144
+ assert_match(/-e\s+ iso-8859-1/x, cmd)
145
+ end
146
+
116
147
  private
117
148
  def fakeshell(options = {})
118
149
  output = options.delete(:output) || ""
119
150
  exit_code = options.delete(:exit) || 0
120
151
 
121
152
  cmd = nil
122
- Object.class_eval do
123
- alias_method "real_tick", "`"
124
- define_method("`") do |arg|
125
- cmd = arg
126
- real_tick %{ruby -e"exit #{exit_code}"} # Just to set $?
127
- output
153
+ Open3.singleton_class.class_eval do
154
+ alias_method "real_capture2e", "capture2e"
155
+ define_method("capture2e") do |*argv|
156
+ cmd = argv.join(" ")
157
+ `ruby -e"exit #{exit_code}"` # Just to set $?
158
+ [output, $?]
128
159
  end
129
160
  end
130
161
 
131
162
  yield
132
- cmd.tr %{"}, %{'} # replace Win quotes with *nix
163
+ cmd
133
164
  ensure
134
- Object.class_eval do
135
- undef_method "`" #`
136
- alias_method "`", "real_tick"
137
- undef_method "real_tick"
165
+ Open3.singleton_class.class_eval do
166
+ undef_method "capture2e"
167
+ alias_method "capture2e", "real_capture2e"
168
+ undef_method "real_capture2e"
138
169
  end
139
170
  end
140
171
  end
metadata CHANGED
@@ -1,14 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ruby-jing
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.2
4
+ version: 0.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Skye Shaw
8
- autorequire:
9
8
  bindir: bin
10
9
  cert_chain: []
11
- date: 2021-10-16 00:00:00.000000000 Z
10
+ date: 2026-09-17 00:00:00.000000000 Z
12
11
  dependencies:
13
12
  - !ruby/object:Gem::Dependency
14
13
  name: optout
@@ -24,6 +23,20 @@ dependencies:
24
23
  - - ">="
25
24
  - !ruby/object:Gem::Version
26
25
  version: 0.0.2
26
+ - !ruby/object:Gem::Dependency
27
+ name: bundler
28
+ requirement: !ruby/object:Gem::Requirement
29
+ requirements:
30
+ - - ">="
31
+ - !ruby/object:Gem::Version
32
+ version: '0'
33
+ type: :development
34
+ prerelease: false
35
+ version_requirements: !ruby/object:Gem::Requirement
36
+ requirements:
37
+ - - ">="
38
+ - !ruby/object:Gem::Version
39
+ version: '0'
27
40
  - !ruby/object:Gem::Dependency
28
41
  name: rake
29
42
  requirement: !ruby/object:Gem::Requirement
@@ -69,8 +82,11 @@ files:
69
82
  homepage: http://github.com/sshaw/ruby-jing
70
83
  licenses:
71
84
  - MIT
72
- metadata: {}
73
- post_install_message:
85
+ metadata:
86
+ homepage_uri: http://github.com/sshaw/ruby-jing
87
+ source_code_uri: https://github.com/sshaw/ruby-jing
88
+ bug_tracker_uri: https://github.com/sshaw/ruby-jing/issues
89
+ changelog_uri: https://github.com/sshaw/ruby-jing/blob/master/Changes
74
90
  rdoc_options: []
75
91
  require_paths:
76
92
  - lib
@@ -85,9 +101,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
85
101
  - !ruby/object:Gem::Version
86
102
  version: '0'
87
103
  requirements: []
88
- rubyforge_project:
89
- rubygems_version: 2.6.14
90
- signing_key:
104
+ rubygems_version: 3.6.2
91
105
  specification_version: 4
92
106
  summary: RELAX NG schema validation using the Jing CLI
93
107
  test_files: