moxml 0.1.0 → 0.1.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.github/workflows/rake.yml +15 -0
- data/.github/workflows/release.yml +23 -0
- data/.gitignore +3 -0
- data/.rubocop.yml +2 -0
- data/.rubocop_todo.yml +65 -0
- data/.ruby-version +1 -0
- data/Gemfile +10 -3
- data/README.adoc +401 -594
- data/lib/moxml/adapter/base.rb +102 -0
- data/lib/moxml/adapter/customized_oga/xml_declaration.rb +18 -0
- data/lib/moxml/adapter/customized_oga/xml_generator.rb +104 -0
- data/lib/moxml/adapter/nokogiri.rb +319 -0
- data/lib/moxml/adapter/oga.rb +318 -0
- data/lib/moxml/adapter/ox.rb +325 -0
- data/lib/moxml/adapter.rb +26 -170
- data/lib/moxml/attribute.rb +47 -14
- data/lib/moxml/builder.rb +64 -0
- data/lib/moxml/cdata.rb +4 -26
- data/lib/moxml/comment.rb +6 -22
- data/lib/moxml/config.rb +39 -15
- data/lib/moxml/context.rb +29 -0
- data/lib/moxml/declaration.rb +16 -26
- data/lib/moxml/doctype.rb +9 -0
- data/lib/moxml/document.rb +51 -63
- data/lib/moxml/document_builder.rb +87 -0
- data/lib/moxml/element.rb +63 -97
- data/lib/moxml/error.rb +20 -0
- data/lib/moxml/namespace.rb +12 -37
- data/lib/moxml/node.rb +78 -58
- data/lib/moxml/node_set.rb +19 -222
- data/lib/moxml/processing_instruction.rb +6 -25
- data/lib/moxml/text.rb +4 -26
- data/lib/moxml/version.rb +1 -1
- data/lib/moxml/xml_utils/encoder.rb +55 -0
- data/lib/moxml/xml_utils.rb +80 -0
- data/lib/moxml.rb +33 -33
- data/moxml.gemspec +1 -1
- data/spec/moxml/adapter/nokogiri_spec.rb +14 -0
- data/spec/moxml/adapter/oga_spec.rb +14 -0
- data/spec/moxml/adapter/ox_spec.rb +49 -0
- data/spec/moxml/all_with_adapters_spec.rb +46 -0
- data/spec/moxml/config_spec.rb +55 -0
- data/spec/moxml/error_spec.rb +71 -0
- data/spec/moxml/examples/adapter_spec.rb +27 -0
- data/spec/moxml_spec.rb +50 -0
- data/spec/spec_helper.rb +32 -0
- data/spec/support/shared_examples/attribute.rb +165 -0
- data/spec/support/shared_examples/builder.rb +25 -0
- data/spec/support/shared_examples/cdata.rb +70 -0
- data/spec/support/shared_examples/comment.rb +65 -0
- data/spec/support/shared_examples/context.rb +35 -0
- data/spec/support/shared_examples/declaration.rb +93 -0
- data/spec/support/shared_examples/doctype.rb +25 -0
- data/spec/support/shared_examples/document.rb +110 -0
- data/spec/support/shared_examples/document_builder.rb +43 -0
- data/spec/support/shared_examples/edge_cases.rb +185 -0
- data/spec/support/shared_examples/element.rb +130 -0
- data/spec/support/shared_examples/examples/attribute.rb +42 -0
- data/spec/support/shared_examples/examples/basic_usage.rb +67 -0
- data/spec/support/shared_examples/examples/memory.rb +54 -0
- data/spec/support/shared_examples/examples/namespace.rb +65 -0
- data/spec/support/shared_examples/examples/readme_examples.rb +100 -0
- data/spec/support/shared_examples/examples/thread_safety.rb +43 -0
- data/spec/support/shared_examples/examples/xpath.rb +39 -0
- data/spec/support/shared_examples/integration.rb +135 -0
- data/spec/support/shared_examples/namespace.rb +96 -0
- data/spec/support/shared_examples/node.rb +110 -0
- data/spec/support/shared_examples/node_set.rb +90 -0
- data/spec/support/shared_examples/processing_instruction.rb +88 -0
- data/spec/support/shared_examples/text.rb +66 -0
- data/spec/support/shared_examples/xml_adapter.rb +191 -0
- data/spec/support/xml_matchers.rb +27 -0
- metadata +55 -6
- data/.github/workflows/main.yml +0 -27
- data/lib/moxml/error_handler.rb +0 -77
- data/lib/moxml/errors.rb +0 -169
@@ -0,0 +1,80 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative "xml_utils/encoder"
|
4
|
+
|
5
|
+
# Ruby 3.3+ requires the URI module to be explicitly required
|
6
|
+
require "uri" unless defined?(::URI)
|
7
|
+
|
8
|
+
module Moxml
|
9
|
+
module XmlUtils
|
10
|
+
def encode_entities(text, mode = nil)
|
11
|
+
Encoder.new(text, mode).call
|
12
|
+
end
|
13
|
+
|
14
|
+
def validate_declaration_version(version)
|
15
|
+
return if ::Moxml::Declaration::ALLOWED_VERSIONS.include?(version)
|
16
|
+
|
17
|
+
raise ValidationError, "Invalid XML version: #{version}"
|
18
|
+
end
|
19
|
+
|
20
|
+
def validate_declaration_encoding(encoding)
|
21
|
+
return if encoding.nil?
|
22
|
+
|
23
|
+
begin
|
24
|
+
Encoding.find(encoding)
|
25
|
+
rescue ArgumentError
|
26
|
+
raise ValidationError, "Invalid encoding: #{encoding}"
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
def validate_declaration_standalone(standalone)
|
31
|
+
return if standalone.nil?
|
32
|
+
return if ::Moxml::Declaration::ALLOWED_STANDALONE.include?(standalone)
|
33
|
+
|
34
|
+
raise ValidationError, "Invalid standalone value: #{standalone}"
|
35
|
+
end
|
36
|
+
|
37
|
+
def validate_comment_content(text)
|
38
|
+
if text.start_with?("-") || text.end_with?("-")
|
39
|
+
raise ValidationError, "XML comment cannot start or end with a hyphen"
|
40
|
+
end
|
41
|
+
|
42
|
+
return unless text.include?("--")
|
43
|
+
|
44
|
+
raise ValidationError, "XML comment cannot contain double hyphens (--)"
|
45
|
+
end
|
46
|
+
|
47
|
+
def validate_element_name(name)
|
48
|
+
return if name.is_a?(String) && name.match?(/^[a-zA-Z_][\w\-.:]*$/)
|
49
|
+
|
50
|
+
raise ValidationError, "Invalid XML name: #{name}"
|
51
|
+
end
|
52
|
+
|
53
|
+
def validate_pi_target(target)
|
54
|
+
return if target.is_a?(String) && target.match?(/^[a-zA-Z_][\w\-.]*$/)
|
55
|
+
|
56
|
+
raise ValidationError, "Invalid XML target: #{target}"
|
57
|
+
end
|
58
|
+
|
59
|
+
def validate_uri(uri)
|
60
|
+
return if uri.empty? || uri.match?(/\A#{::URI::DEFAULT_PARSER.make_regexp}\z/)
|
61
|
+
|
62
|
+
raise ValidationError, "Invalid URI: #{uri}"
|
63
|
+
end
|
64
|
+
|
65
|
+
def validate_prefix(prefix)
|
66
|
+
return if prefix.match?(/\A[a-zA-Z_][\w-]*\z/)
|
67
|
+
|
68
|
+
raise ValidationError, "Invalid namespace prefix: #{prefix}"
|
69
|
+
end
|
70
|
+
|
71
|
+
def normalize_xml_value(value)
|
72
|
+
case value
|
73
|
+
when nil then ""
|
74
|
+
when true then "true"
|
75
|
+
when false then "false"
|
76
|
+
else value.to_s
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
data/lib/moxml.rb
CHANGED
@@ -1,44 +1,44 @@
|
|
1
|
-
#
|
2
|
-
require_relative "moxml/version"
|
3
|
-
require_relative "moxml/config"
|
4
|
-
require_relative "moxml/document"
|
5
|
-
require_relative "moxml/node"
|
6
|
-
require_relative "moxml/element"
|
7
|
-
require_relative "moxml/text"
|
8
|
-
require_relative "moxml/cdata_section"
|
9
|
-
require_relative "moxml/comment"
|
10
|
-
require_relative "moxml/processing_instruction"
|
11
|
-
require_relative "moxml/visitor"
|
12
|
-
require_relative "moxml/errors"
|
13
|
-
require_relative "moxml/backends/base"
|
1
|
+
# frozen_string_literal: true
|
14
2
|
|
15
3
|
module Moxml
|
16
4
|
class << self
|
17
|
-
def
|
18
|
-
|
5
|
+
def new(adapter = nil, &block)
|
6
|
+
context = Context.new(adapter)
|
7
|
+
context.config.instance_eval(&block) if block_given?
|
8
|
+
context
|
19
9
|
end
|
20
10
|
|
21
11
|
def configure
|
22
|
-
yield
|
12
|
+
yield Config.default if block_given?
|
23
13
|
end
|
24
14
|
|
25
|
-
def
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
15
|
+
def with_config(adapter_name = nil, strict_parsing = nil, default_encoding = nil)
|
16
|
+
original_config = Config.default.dup
|
17
|
+
|
18
|
+
configure do |config|
|
19
|
+
config.adapter = adapter_name unless adapter_name.nil?
|
20
|
+
config.strict_parsing = strict_parsing unless strict_parsing.nil?
|
21
|
+
config.default_encoding = default_encoding unless default_encoding.nil?
|
22
|
+
end
|
23
|
+
|
24
|
+
yield if block_given?
|
25
|
+
|
26
|
+
# restore the original config
|
27
|
+
configure do |config|
|
28
|
+
config.adapter = original_config.adapter_name
|
29
|
+
config.strict_parsing = original_config.strict_parsing
|
30
|
+
config.default_encoding = original_config.default_encoding
|
31
|
+
end
|
32
|
+
original_config = nil
|
42
33
|
end
|
43
34
|
end
|
44
35
|
end
|
36
|
+
|
37
|
+
require_relative "moxml/version"
|
38
|
+
require_relative "moxml/document"
|
39
|
+
require_relative "moxml/document_builder"
|
40
|
+
require_relative "moxml/error"
|
41
|
+
require_relative "moxml/builder"
|
42
|
+
require_relative "moxml/config"
|
43
|
+
require_relative "moxml/context"
|
44
|
+
require_relative "moxml/adapter"
|
data/moxml.gemspec
CHANGED
@@ -25,7 +25,7 @@ Gem::Specification.new do |spec|
|
|
25
25
|
# RubyGem that have been added into git.
|
26
26
|
spec.files = Dir.chdir(File.expand_path(__dir__)) do
|
27
27
|
`git ls-files -z`.split("\x0").reject do |f|
|
28
|
-
f.match(%r{^(test|
|
28
|
+
f.match(%r{^(test|features)/})
|
29
29
|
end
|
30
30
|
end
|
31
31
|
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
@@ -0,0 +1,14 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "nokogiri"
|
4
|
+
require "moxml/adapter/nokogiri"
|
5
|
+
|
6
|
+
RSpec.describe Moxml::Adapter::Nokogiri do
|
7
|
+
around do |example|
|
8
|
+
Moxml.with_config(:nokogiri, true, "UTF-8") do
|
9
|
+
example.run
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
it_behaves_like "xml adapter"
|
14
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "oga"
|
4
|
+
require "moxml/adapter/oga"
|
5
|
+
|
6
|
+
RSpec.describe Moxml::Adapter::Oga do
|
7
|
+
around do |example|
|
8
|
+
Moxml.with_config(:oga, true, "UTF-8") do
|
9
|
+
example.run
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
it_behaves_like "xml adapter"
|
14
|
+
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "ox"
|
4
|
+
require "moxml/adapter/ox"
|
5
|
+
|
6
|
+
RSpec.describe Moxml::Adapter::Ox, skip: "Ox will be added later" do
|
7
|
+
before(:all) do
|
8
|
+
Moxml.configure do |config|
|
9
|
+
config.adapter = :ox
|
10
|
+
config.strict_parsing = true
|
11
|
+
config.default_encoding = "UTF-8"
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
it_behaves_like "xml adapter"
|
16
|
+
|
17
|
+
describe "text handling" do
|
18
|
+
let(:doc) { described_class.create_document }
|
19
|
+
let(:element) { described_class.create_native_element("test") }
|
20
|
+
|
21
|
+
it "creates text nodes as strings" do
|
22
|
+
text = described_class.create_native_text("content")
|
23
|
+
expect(text).to be_a(String)
|
24
|
+
expect(text).to eq("content")
|
25
|
+
end
|
26
|
+
|
27
|
+
it "adds text nodes to elements" do
|
28
|
+
text = described_class.create_native_text("content")
|
29
|
+
described_class.add_child(element, text)
|
30
|
+
expect(element.nodes.first).to eq("content")
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
describe "xpath support" do
|
35
|
+
let(:doc) { described_class.parse("<root><child id='1'>text</child></root>") }
|
36
|
+
|
37
|
+
it "supports basic element matching" do
|
38
|
+
nodes = described_class.xpath(doc, "//child")
|
39
|
+
expect(nodes.size).to eq(1)
|
40
|
+
expect(nodes.first.name).to eq("child")
|
41
|
+
end
|
42
|
+
|
43
|
+
it "supports attribute matching" do
|
44
|
+
nodes = described_class.xpath(doc, "//child[@id='1']")
|
45
|
+
expect(nodes.size).to eq(1)
|
46
|
+
expect(nodes.first.attributes["id"]).to eq("1")
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
RSpec.describe "Test all shared examples" do
|
4
|
+
all_shared_examples = [
|
5
|
+
"Moxml::Node",
|
6
|
+
"Moxml::Namespace",
|
7
|
+
"Moxml::Attribute",
|
8
|
+
"Moxml::NodeSet",
|
9
|
+
"Moxml::Element",
|
10
|
+
"Moxml::Cdata",
|
11
|
+
"Moxml::Comment",
|
12
|
+
"Moxml::Text",
|
13
|
+
"Moxml::ProcessingInstruction",
|
14
|
+
"Moxml::Declaration",
|
15
|
+
"Moxml::Doctype",
|
16
|
+
"Moxml::Document",
|
17
|
+
"Moxml::Context",
|
18
|
+
"Moxml::Builder",
|
19
|
+
"Moxml::DocumentBuilder",
|
20
|
+
"Moxml Integration",
|
21
|
+
"Moxml Edge Cases",
|
22
|
+
"Attribute Examples",
|
23
|
+
"Basic Usage Examples",
|
24
|
+
"Namespace Examples",
|
25
|
+
"README Examples",
|
26
|
+
"XPath Examples",
|
27
|
+
"Memory Usage Examples",
|
28
|
+
"Thread Safety Examples"
|
29
|
+
]
|
30
|
+
|
31
|
+
Moxml::Adapter::AVALIABLE_ADAPTERS.each do |adapter_name|
|
32
|
+
# [:nokogiri].each do |adapter_name|
|
33
|
+
# [:oga].each do |adapter_name|
|
34
|
+
context "with #{adapter_name}" do
|
35
|
+
around do |example|
|
36
|
+
Moxml.with_config(adapter_name) do
|
37
|
+
example.run
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
all_shared_examples.each do |shared_example_name|
|
42
|
+
it_behaves_like shared_example_name
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
@@ -0,0 +1,55 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# spec/moxml/config_spec.rb
|
4
|
+
RSpec.describe Moxml::Config do
|
5
|
+
subject(:config) { described_class.new }
|
6
|
+
|
7
|
+
describe "#initialize" do
|
8
|
+
it "sets default values" do
|
9
|
+
expect(config.adapter_name).to eq(:nokogiri)
|
10
|
+
expect(config.strict_parsing).to be true
|
11
|
+
expect(config.default_encoding).to eq("UTF-8")
|
12
|
+
expect(config.default_indent).to eq(2)
|
13
|
+
expect(config.entity_encoding).to eq(:basic)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
describe "#adapter=" do
|
18
|
+
it "sets valid adapter" do
|
19
|
+
config.adapter = :ox
|
20
|
+
expect(config.adapter_name).to eq(:ox)
|
21
|
+
end
|
22
|
+
|
23
|
+
it "raises error for invalid adapter" do
|
24
|
+
expect { config.adapter = :invalid }.to raise_error(ArgumentError)
|
25
|
+
end
|
26
|
+
|
27
|
+
it "requires adapter gem" do
|
28
|
+
expect { config.adapter = :oga }.not_to raise_error
|
29
|
+
|
30
|
+
expect(defined?(::Oga)).to be_truthy
|
31
|
+
end
|
32
|
+
|
33
|
+
it "handles missing gems" do
|
34
|
+
allow(Moxml::Adapter).to receive(:require).and_raise(LoadError)
|
35
|
+
expect { config.adapter = :nokogiri }.to raise_error(LoadError)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
describe "#adapter" do
|
40
|
+
it "returns nokogiri adapter by default" do
|
41
|
+
expect(config.adapter).to eq(Moxml::Adapter::Nokogiri)
|
42
|
+
end
|
43
|
+
|
44
|
+
it "caches adapter instance" do
|
45
|
+
adapter = config.adapter
|
46
|
+
expect(config.adapter.object_id).to eq(adapter.object_id)
|
47
|
+
end
|
48
|
+
|
49
|
+
it "resets cached adapter when changing adapter type" do
|
50
|
+
original = config.adapter
|
51
|
+
config.adapter = :ox
|
52
|
+
expect(config.adapter).not_to eq(original)
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
@@ -0,0 +1,71 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# spec/moxml/errors_spec.rb
|
4
|
+
RSpec.describe "Moxml errors" do
|
5
|
+
describe Moxml::Error do
|
6
|
+
it "is a StandardError" do
|
7
|
+
expect(Moxml::Error.new).to be_a(StandardError)
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
describe Moxml::ParseError do
|
12
|
+
it "includes line and column information" do
|
13
|
+
error = Moxml::ParseError.new("Invalid XML", line: 5, column: 10)
|
14
|
+
expect(error.line).to eq(5)
|
15
|
+
expect(error.column).to eq(10)
|
16
|
+
expect(error.message).to eq("Invalid XML")
|
17
|
+
end
|
18
|
+
|
19
|
+
it "works without line and column" do
|
20
|
+
error = Moxml::ParseError.new("Invalid XML")
|
21
|
+
expect(error.line).to be_nil
|
22
|
+
expect(error.column).to be_nil
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
describe Moxml::ValidationError do
|
27
|
+
it "handles validation errors" do
|
28
|
+
error = Moxml::ValidationError.new("Invalid document structure")
|
29
|
+
expect(error.message).to eq("Invalid document structure")
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
describe Moxml::XPathError do
|
34
|
+
it "handles XPath errors" do
|
35
|
+
error = Moxml::XPathError.new("Invalid XPath expression")
|
36
|
+
expect(error.message).to eq("Invalid XPath expression")
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
describe Moxml::NamespaceError do
|
41
|
+
it "handles namespace errors" do
|
42
|
+
error = Moxml::NamespaceError.new("Invalid namespace URI")
|
43
|
+
expect(error.message).to eq("Invalid namespace URI")
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
describe "error handling in context" do
|
48
|
+
let(:context) { Moxml.new }
|
49
|
+
|
50
|
+
it "raises ParseError for invalid XML" do
|
51
|
+
expect do
|
52
|
+
context.parse("<invalid>")
|
53
|
+
end.to raise_error(Moxml::ParseError)
|
54
|
+
end
|
55
|
+
|
56
|
+
it "raises XPathError for invalid XPath" do
|
57
|
+
doc = context.parse("<root/>")
|
58
|
+
expect do
|
59
|
+
doc.xpath("///")
|
60
|
+
end.to raise_error(Moxml::XPathError)
|
61
|
+
end
|
62
|
+
|
63
|
+
it "raises NamespaceError for invalid namespace" do
|
64
|
+
doc = context.parse("<root/>")
|
65
|
+
|
66
|
+
expect do
|
67
|
+
doc.root.add_namespace("xml", "http//invalid.com")
|
68
|
+
end.to raise_error(Moxml::NamespaceError, "Invalid URI: http//invalid.com")
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
RSpec.describe "Adapter Examples" do
|
4
|
+
let(:xml) { "<root><child>text</child></root>" }
|
5
|
+
|
6
|
+
describe "Serialization consistency" do
|
7
|
+
it "produces equivalent XML across adapters",
|
8
|
+
skip: "No easy way to exclude the declaration from Nokogiri documents" do
|
9
|
+
docs = Moxml::Adapter::AVALIABLE_ADAPTERS.map do |adapter|
|
10
|
+
Moxml.new(adapter).parse(xml, fragment: true)
|
11
|
+
end
|
12
|
+
|
13
|
+
xmls = docs.map { |doc| normalize_xml(doc.to_xml) }
|
14
|
+
expect(xmls.uniq.size).to eq(1)
|
15
|
+
end
|
16
|
+
|
17
|
+
private
|
18
|
+
|
19
|
+
def normalize_xml(xml)
|
20
|
+
xml.gsub(/>\s+</, "><")
|
21
|
+
.gsub(/\s+/, " ")
|
22
|
+
.gsub(/ >/, ">")
|
23
|
+
.gsub(/\?></, "?>\n<")
|
24
|
+
.strip
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
data/spec/moxml_spec.rb
ADDED
@@ -0,0 +1,50 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# spec/moxml_spec.rb
|
4
|
+
RSpec.describe Moxml do
|
5
|
+
it "has a version number" do
|
6
|
+
expect(Moxml::VERSION).not_to be_nil
|
7
|
+
end
|
8
|
+
|
9
|
+
describe ".new" do
|
10
|
+
it "creates a new context" do
|
11
|
+
expect(Moxml.new).to be_a(Moxml::Context)
|
12
|
+
end
|
13
|
+
|
14
|
+
it "accepts adapter specification" do
|
15
|
+
context = Moxml.new(:nokogiri)
|
16
|
+
expect(context.config.adapter_name).to eq(:nokogiri)
|
17
|
+
end
|
18
|
+
|
19
|
+
it "raises error for invalid adapter" do
|
20
|
+
expect { Moxml.new(:invalid) }.to raise_error(ArgumentError)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
describe ".configure" do
|
25
|
+
around do |example|
|
26
|
+
# preserve the original config because it may be changed in examples
|
27
|
+
Moxml.with_config { example.run }
|
28
|
+
end
|
29
|
+
|
30
|
+
it "sets default values without a block" do
|
31
|
+
Moxml.configure
|
32
|
+
|
33
|
+
context = Moxml.new
|
34
|
+
expect(context.config.adapter_name).to eq(:nokogiri)
|
35
|
+
end
|
36
|
+
|
37
|
+
it "uses configured options from the block" do
|
38
|
+
Moxml.configure do |config|
|
39
|
+
config.adapter = :oga
|
40
|
+
config.strict_parsing = false
|
41
|
+
config.default_encoding = "US-ASCII"
|
42
|
+
end
|
43
|
+
|
44
|
+
context = Moxml.new
|
45
|
+
expect(context.config.adapter_name).to eq(:oga)
|
46
|
+
expect(context.config.strict_parsing).to eq(false)
|
47
|
+
expect(context.config.default_encoding).to eq("US-ASCII")
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,32 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "moxml"
|
4
|
+
require "nokogiri"
|
5
|
+
require "byebug"
|
6
|
+
|
7
|
+
Dir[File.expand_path("support/**/*.rb", __dir__)].each { |f| require f }
|
8
|
+
|
9
|
+
RSpec.configure do |config|
|
10
|
+
config.expect_with :rspec do |expectations|
|
11
|
+
expectations.include_chain_clauses_in_custom_matcher_descriptions = true
|
12
|
+
end
|
13
|
+
|
14
|
+
config.mock_with :rspec do |mocks|
|
15
|
+
mocks.verify_partial_doubles = true
|
16
|
+
end
|
17
|
+
|
18
|
+
config.shared_context_metadata_behavior = :apply_to_host_groups
|
19
|
+
config.filter_run_when_matching :focus
|
20
|
+
config.example_status_persistence_file_path = "spec/examples.txt"
|
21
|
+
config.disable_monkey_patching!
|
22
|
+
config.warnings = true
|
23
|
+
|
24
|
+
config.order = :random
|
25
|
+
Kernel.srand config.seed
|
26
|
+
end
|
27
|
+
|
28
|
+
Moxml.configure do |config|
|
29
|
+
config.adapter = :nokogiri
|
30
|
+
config.strict_parsing = true
|
31
|
+
config.default_encoding = "UTF-8"
|
32
|
+
end
|