saxerator 0.9.5 → 0.9.8
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.
- checksums.yaml +4 -4
- data/.gitignore +2 -0
- data/.travis.yml +9 -12
- data/Gemfile +4 -2
- data/README.md +23 -3
- data/Rakefile +12 -1
- data/benchmark/benchmark.rb +54 -12
- data/benchmark/generate_sample_file.rb +1 -1
- data/lib/saxerator.rb +2 -3
- data/lib/saxerator/adapters/nokogiri.rb +39 -0
- data/lib/saxerator/adapters/ox.rb +69 -0
- data/lib/saxerator/adapters/rexml.rb +42 -0
- data/lib/saxerator/builder.rb +2 -2
- data/lib/saxerator/builder/array_element.rb +8 -2
- data/lib/saxerator/builder/empty_element.rb +2 -3
- data/lib/saxerator/builder/hash_builder.rb +8 -7
- data/lib/saxerator/builder/hash_element.rb +7 -8
- data/lib/saxerator/builder/string_element.rb +5 -7
- data/lib/saxerator/builder/xml_builder.rb +11 -7
- data/lib/saxerator/configuration.rb +27 -7
- data/lib/saxerator/document_fragment.rb +3 -5
- data/lib/saxerator/dsl.rb +6 -5
- data/lib/saxerator/full_document.rb +1 -1
- data/lib/saxerator/latches/abstract_latch.rb +1 -1
- data/lib/saxerator/latches/at_depth.rb +2 -2
- data/lib/saxerator/latches/child_of.rb +9 -14
- data/lib/saxerator/latches/for_tags.rb +2 -2
- data/lib/saxerator/latches/with_attributes.rb +2 -2
- data/lib/saxerator/latches/within.rb +6 -10
- data/lib/saxerator/parser/accumulator.rb +6 -9
- data/lib/saxerator/parser/latched_accumulator.rb +4 -49
- data/lib/saxerator/sax_handler.rb +9 -0
- data/lib/saxerator/version.rb +1 -1
- data/saxerator.gemspec +5 -2
- data/spec/lib/builder/hash_builder_spec.rb +25 -19
- data/spec/lib/builder/xml_builder_spec.rb +7 -26
- data/spec/lib/dsl/all_spec.rb +11 -6
- data/spec/lib/dsl/at_depth_spec.rb +10 -8
- data/spec/lib/dsl/child_of_spec.rb +6 -6
- data/spec/lib/dsl/for_tag_spec.rb +3 -3
- data/spec/lib/dsl/for_tags_spec.rb +5 -5
- data/spec/lib/dsl/with_attribute_spec.rb +4 -4
- data/spec/lib/dsl/with_attributes_spec.rb +8 -7
- data/spec/lib/dsl/within_spec.rb +6 -5
- data/spec/lib/saxerator_spec.rb +70 -58
- data/spec/spec_helper.rb +24 -3
- data/spec/support/fixture_file.rb +1 -1
- metadata +39 -5
@@ -1,21 +1,20 @@
|
|
1
1
|
require 'saxerator/builder/array_element'
|
2
|
+
require 'delegate'
|
2
3
|
|
3
4
|
module Saxerator
|
4
5
|
module Builder
|
5
|
-
class HashElement < Hash
|
6
|
+
class HashElement < DelegateClass(Hash)
|
6
7
|
attr_accessor :attributes
|
7
8
|
attr_accessor :name
|
8
9
|
|
9
|
-
def initialize(name, attributes)
|
10
|
-
|
11
|
-
|
10
|
+
def initialize(name = nil, attributes = nil)
|
11
|
+
@name = name
|
12
|
+
@attributes = attributes
|
13
|
+
super({})
|
12
14
|
end
|
13
15
|
|
14
16
|
def to_a
|
15
|
-
|
16
|
-
array.name = name
|
17
|
-
array.concat super
|
18
|
-
array
|
17
|
+
ArrayElement.new(super, name)
|
19
18
|
end
|
20
19
|
|
21
20
|
def to_h; self end
|
@@ -1,22 +1,20 @@
|
|
1
1
|
require 'saxerator/builder/array_element'
|
2
|
+
require 'delegate'
|
2
3
|
|
3
4
|
module Saxerator
|
4
5
|
module Builder
|
5
|
-
class StringElement < String
|
6
|
+
class StringElement < DelegateClass(String)
|
6
7
|
attr_accessor :attributes
|
7
8
|
attr_accessor :name
|
8
9
|
|
9
10
|
def initialize(str, name, attributes)
|
10
|
-
|
11
|
-
|
11
|
+
@name = name
|
12
|
+
@attributes = attributes
|
12
13
|
super(str)
|
13
14
|
end
|
14
15
|
|
15
16
|
def to_a
|
16
|
-
|
17
|
-
array << self
|
18
|
-
array.name = name
|
19
|
-
array
|
17
|
+
ArrayElement.new(self, name)
|
20
18
|
end
|
21
19
|
end
|
22
20
|
end
|
@@ -1,3 +1,5 @@
|
|
1
|
+
require 'rexml/document'
|
2
|
+
|
1
3
|
module Saxerator
|
2
4
|
module Builder
|
3
5
|
class XmlBuilder
|
@@ -17,20 +19,22 @@ module Saxerator
|
|
17
19
|
end
|
18
20
|
|
19
21
|
def to_xml(builder)
|
22
|
+
element = REXML::Element.new(name, nil, attribute_quote: :quote)
|
23
|
+
element.add_attributes(@attributes)
|
20
24
|
if @text
|
21
|
-
|
25
|
+
element.add_text(@children.join)
|
22
26
|
else
|
23
|
-
|
24
|
-
@children.each { |child| child.to_xml(xml) }
|
25
|
-
end
|
27
|
+
@children.each { |child| child.to_xml(element) }
|
26
28
|
end
|
29
|
+
builder.elements << element
|
27
30
|
end
|
28
31
|
|
29
32
|
def block_variable
|
30
|
-
builder =
|
33
|
+
builder = REXML::Document.new
|
34
|
+
builder << REXML::XMLDecl.new('1.0', 'UTF-8')
|
31
35
|
to_xml(builder)
|
32
|
-
builder
|
36
|
+
builder
|
33
37
|
end
|
34
38
|
end
|
35
39
|
end
|
36
|
-
end
|
40
|
+
end
|
@@ -1,26 +1,45 @@
|
|
1
1
|
module Saxerator
|
2
2
|
class Configuration
|
3
|
-
attr_reader :output_type
|
4
3
|
attr_writer :hash_key_generator
|
4
|
+
attr_reader :output_type
|
5
|
+
|
6
|
+
ADAPTER_TYPES = [:ox, :nokogiri, :rexml]
|
5
7
|
|
6
8
|
def initialize
|
9
|
+
@adapter = :rexml
|
7
10
|
@output_type = :hash
|
8
11
|
@put_attributes_in_hash = false
|
9
12
|
@ignore_namespaces = false
|
10
13
|
end
|
11
14
|
|
15
|
+
def adapter=(name)
|
16
|
+
unless ADAPTER_TYPES.include?(name)
|
17
|
+
raise ArgumentError, "Unknown adapter '#{name.inspect}'"
|
18
|
+
end
|
19
|
+
@adapter = name
|
20
|
+
end
|
21
|
+
|
22
|
+
def adapter
|
23
|
+
require "saxerator/adapters/#{@adapter}"
|
24
|
+
Saxerator::Adapters.const_get(@adapter.to_s.capitalize, false)
|
25
|
+
end
|
26
|
+
|
12
27
|
def output_type=(val)
|
13
|
-
raise ArgumentError
|
28
|
+
raise ArgumentError, "Unknown output_type '#{val.inspect}'" unless Builder.valid?(val)
|
14
29
|
@output_type = val
|
15
30
|
raise_error_if_using_put_attributes_in_hash_with_xml
|
16
31
|
end
|
17
32
|
|
33
|
+
def output_type
|
34
|
+
@_output_type ||= Builder.to_class(@output_type)
|
35
|
+
end
|
36
|
+
|
18
37
|
def generate_key_for(val)
|
19
38
|
hash_key_generator.call val
|
20
39
|
end
|
21
40
|
|
22
41
|
def hash_key_normalizer
|
23
|
-
@hash_key_normalizer ||=
|
42
|
+
@hash_key_normalizer ||= -> (x) { x.to_s }
|
24
43
|
end
|
25
44
|
|
26
45
|
def hash_key_generator
|
@@ -28,15 +47,15 @@ module Saxerator
|
|
28
47
|
end
|
29
48
|
|
30
49
|
def symbolize_keys!
|
31
|
-
@hash_key_generator =
|
50
|
+
@hash_key_generator = -> (x) { hash_key_normalizer.call(x).to_sym }
|
32
51
|
end
|
33
52
|
|
34
53
|
def strip_namespaces!(*namespaces)
|
35
54
|
if namespaces.any?
|
36
55
|
matching_group = namespaces.join('|')
|
37
|
-
@hash_key_normalizer =
|
56
|
+
@hash_key_normalizer = -> (x) { x.to_s.gsub(/(#{matching_group}):/, '') }
|
38
57
|
else
|
39
|
-
@hash_key_normalizer =
|
58
|
+
@hash_key_normalizer = -> (x) { x.to_s.gsub(/\w+:/, '') }
|
40
59
|
end
|
41
60
|
end
|
42
61
|
|
@@ -59,7 +78,8 @@ module Saxerator
|
|
59
78
|
|
60
79
|
def raise_error_if_using_put_attributes_in_hash_with_xml
|
61
80
|
if @output_type != :hash && @put_attributes_in_hash
|
62
|
-
raise ArgumentError
|
81
|
+
raise ArgumentError, "put_attributes_in_hash! is only valid \
|
82
|
+
when using output_type = :hash (the default)'"
|
63
83
|
end
|
64
84
|
end
|
65
85
|
end
|
@@ -10,13 +10,11 @@ module Saxerator
|
|
10
10
|
end
|
11
11
|
|
12
12
|
def each(&block)
|
13
|
-
reader = Parser::LatchedAccumulator.new(@config, @latches, block)
|
14
|
-
parser = Nokogiri::XML::SAX::Parser.new(reader)
|
15
|
-
|
16
13
|
# Always have to start at the beginning of a File
|
17
14
|
@source.rewind if @source.respond_to?(:rewind)
|
18
15
|
|
19
|
-
|
16
|
+
reader = Parser::LatchedAccumulator.new(@config, @latches, block)
|
17
|
+
@config.adapter.parse(@source, reader)
|
20
18
|
end
|
21
19
|
end
|
22
|
-
end
|
20
|
+
end
|
data/lib/saxerator/dsl.rb
CHANGED
@@ -5,7 +5,7 @@ module Saxerator
|
|
5
5
|
end
|
6
6
|
|
7
7
|
def for_tags(tags)
|
8
|
-
raise ArgumentError
|
8
|
+
raise ArgumentError, '#for_tags requires an Array argument' unless tags.is_a? Array
|
9
9
|
specify Latches::ForTags.new(tags.map(&:to_s))
|
10
10
|
end
|
11
11
|
|
@@ -22,21 +22,22 @@ module Saxerator
|
|
22
22
|
end
|
23
23
|
|
24
24
|
def with_attribute(name, value = nil)
|
25
|
-
specify Latches::WithAttributes.new(
|
25
|
+
specify Latches::WithAttributes.new(name.to_s => !value.nil? ? value.to_s : nil)
|
26
26
|
end
|
27
27
|
|
28
28
|
def with_attributes(attrs)
|
29
29
|
if attrs.is_a? Array
|
30
|
-
attrs = Hash[attrs.map { |k| [k, nil]}]
|
30
|
+
attrs = Hash[attrs.map { |k| [k, nil] }]
|
31
31
|
elsif attrs.is_a? Hash
|
32
|
-
attrs = Hash[attrs.map{ |k, v| [k.to_s, v ? v.to_s : v]}]
|
32
|
+
attrs = Hash[attrs.map { |k, v| [k.to_s, v ? v.to_s : v] }]
|
33
33
|
else
|
34
|
-
raise ArgumentError
|
34
|
+
raise ArgumentError, 'attributes should be a Hash or Array'
|
35
35
|
end
|
36
36
|
specify Latches::WithAttributes.new(attrs)
|
37
37
|
end
|
38
38
|
|
39
39
|
private
|
40
|
+
|
40
41
|
def specify(predicate)
|
41
42
|
DocumentFragment.new(@source, @config, @latches + [predicate])
|
42
43
|
end
|
@@ -1,6 +1,6 @@
|
|
1
1
|
module Saxerator
|
2
2
|
module Latches
|
3
|
-
class AtDepth <
|
3
|
+
class AtDepth < ::Saxerator::SaxHandler
|
4
4
|
def initialize(depth)
|
5
5
|
@target_depth = depth
|
6
6
|
@current_depth = -1
|
@@ -19,4 +19,4 @@ module Saxerator
|
|
19
19
|
end
|
20
20
|
end
|
21
21
|
end
|
22
|
-
end
|
22
|
+
end
|
@@ -1,25 +1,20 @@
|
|
1
1
|
module Saxerator
|
2
2
|
module Latches
|
3
|
-
class ChildOf <
|
3
|
+
class ChildOf < ::Saxerator::SaxHandler
|
4
4
|
def initialize(name)
|
5
5
|
@name = name
|
6
6
|
@depths = []
|
7
7
|
end
|
8
8
|
|
9
|
-
def start_element
|
10
|
-
if depth_within_element > 0
|
11
|
-
|
12
|
-
end
|
13
|
-
if @name == name
|
14
|
-
@depths.push 1
|
15
|
-
end
|
9
|
+
def start_element(name, _)
|
10
|
+
increment_depth(1) if depth_within_element > 0
|
11
|
+
@depths.push 1 if @name == name
|
16
12
|
end
|
17
13
|
|
18
|
-
def end_element
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
end
|
14
|
+
def end_element(_)
|
15
|
+
return unless depth_within_element > 0
|
16
|
+
increment_depth(-1)
|
17
|
+
@depths.pop if @depths[-1] == 0
|
23
18
|
end
|
24
19
|
|
25
20
|
def open?
|
@@ -31,7 +26,7 @@ module Saxerator
|
|
31
26
|
end
|
32
27
|
|
33
28
|
def depth_within_element
|
34
|
-
|
29
|
+
!@depths.empty? ? @depths[-1] : 0
|
35
30
|
end
|
36
31
|
end
|
37
32
|
end
|
@@ -7,7 +7,7 @@ module Saxerator
|
|
7
7
|
@attrs = attrs
|
8
8
|
end
|
9
9
|
|
10
|
-
def start_element
|
10
|
+
def start_element(_, attributes)
|
11
11
|
attributes = Hash[attributes]
|
12
12
|
if @attrs.all? { |k, v| attributes[k] && (v.nil? || attributes[k] == v) }
|
13
13
|
open
|
@@ -16,7 +16,7 @@ module Saxerator
|
|
16
16
|
end
|
17
17
|
end
|
18
18
|
|
19
|
-
def end_element
|
19
|
+
def end_element(_)
|
20
20
|
close
|
21
21
|
end
|
22
22
|
end
|
@@ -1,21 +1,17 @@
|
|
1
1
|
module Saxerator
|
2
2
|
module Latches
|
3
|
-
class Within <
|
3
|
+
class Within < ::Saxerator::SaxHandler
|
4
4
|
def initialize(name)
|
5
5
|
@name = name
|
6
6
|
@depth_within_element = 0
|
7
7
|
end
|
8
8
|
|
9
|
-
def start_element
|
10
|
-
if name == @name || @depth_within_element > 0
|
11
|
-
@depth_within_element += 1
|
12
|
-
end
|
9
|
+
def start_element(name, _)
|
10
|
+
@depth_within_element += 1 if name == @name || @depth_within_element > 0
|
13
11
|
end
|
14
12
|
|
15
|
-
def end_element
|
16
|
-
if @depth_within_element > 0
|
17
|
-
@depth_within_element -= 1
|
18
|
-
end
|
13
|
+
def end_element(_)
|
14
|
+
@depth_within_element -= 1 if @depth_within_element > 0
|
19
15
|
end
|
20
16
|
|
21
17
|
def open?
|
@@ -23,4 +19,4 @@ module Saxerator
|
|
23
19
|
end
|
24
20
|
end
|
25
21
|
end
|
26
|
-
end
|
22
|
+
end
|
@@ -1,35 +1,32 @@
|
|
1
1
|
module Saxerator
|
2
2
|
module Parser
|
3
|
-
class Accumulator <
|
3
|
+
class Accumulator < ::Saxerator::SaxHandler
|
4
4
|
def initialize(config, block)
|
5
5
|
@stack = []
|
6
6
|
@config = config
|
7
7
|
@block = block
|
8
|
-
@builder = Builder.to_class(@config.output_type)
|
9
8
|
end
|
10
9
|
|
11
10
|
def start_element(name, attrs = [])
|
12
|
-
@stack.push @
|
11
|
+
@stack.push @config.output_type.new(@config, name, Hash[attrs])
|
13
12
|
end
|
14
13
|
|
15
14
|
def end_element(_)
|
16
15
|
if @stack.size > 1
|
17
16
|
last = @stack.pop
|
18
|
-
@stack.
|
17
|
+
@stack[-1].add_node last
|
19
18
|
else
|
20
19
|
@block.call(@stack.pop.block_variable)
|
21
20
|
end
|
22
21
|
end
|
23
22
|
|
24
23
|
def characters(string)
|
25
|
-
@stack.
|
24
|
+
@stack[-1].add_node(string) unless string.strip.length == 0
|
26
25
|
end
|
27
26
|
|
28
|
-
alias cdata_block characters
|
29
|
-
|
30
27
|
def accumulating?
|
31
|
-
|
28
|
+
!@stack.empty?
|
32
29
|
end
|
33
30
|
end
|
34
31
|
end
|
35
|
-
end
|
32
|
+
end
|
@@ -1,6 +1,6 @@
|
|
1
1
|
module Saxerator
|
2
2
|
module Parser
|
3
|
-
class LatchedAccumulator <
|
3
|
+
class LatchedAccumulator < ::Saxerator::SaxHandler
|
4
4
|
def initialize(config, latches, block)
|
5
5
|
@latches = latches
|
6
6
|
@accumulator = Accumulator.new(config, block)
|
@@ -9,22 +9,7 @@ module Saxerator
|
|
9
9
|
|
10
10
|
def check_latches_and_passthrough(method, *args)
|
11
11
|
@latches.each { |latch| latch.send(method, *args) }
|
12
|
-
if @accumulator.accumulating? ||
|
13
|
-
@latches.all? { |latch| latch.open? }
|
14
|
-
@accumulator.send(method, *args)
|
15
|
-
end
|
16
|
-
end
|
17
|
-
|
18
|
-
def xmldecl(version, encoding, standalone)
|
19
|
-
check_latches_and_passthrough(:xmldecl, version, encoding, standalone)
|
20
|
-
end
|
21
|
-
|
22
|
-
def start_document
|
23
|
-
check_latches_and_passthrough(:start_document)
|
24
|
-
end
|
25
|
-
|
26
|
-
def end_document
|
27
|
-
check_latches_and_passthrough(:end_document)
|
12
|
+
@accumulator.send(method, *args) if @accumulator.accumulating? || @latches.all?(&:open?)
|
28
13
|
end
|
29
14
|
|
30
15
|
def start_element(name, attrs = [])
|
@@ -35,42 +20,12 @@ module Saxerator
|
|
35
20
|
check_latches_and_passthrough(:end_element, name)
|
36
21
|
end
|
37
22
|
|
38
|
-
def start_element_namespace(name, attrs = [], prefix = nil, uri = nil, ns = [])
|
39
|
-
if @ignore_namespaces
|
40
|
-
prefix, uri, ns = nil, nil, []
|
41
|
-
attrs.each do |attr|
|
42
|
-
attr.prefix = nil if attr.respond_to? :prefix
|
43
|
-
attr.uri = nil if attr.respond_to? :uri
|
44
|
-
end
|
45
|
-
end
|
46
|
-
check_latches_and_passthrough(:start_element_namespace, name, attrs, prefix, uri, ns)
|
47
|
-
end
|
48
|
-
|
49
|
-
def end_element_namespace(name, prefix = nil, uri = nil)
|
50
|
-
if @ignore_namespaces
|
51
|
-
prefix, uri = nil
|
52
|
-
end
|
53
|
-
check_latches_and_passthrough(:end_element_namespace, name, prefix, uri)
|
54
|
-
end
|
55
|
-
|
56
23
|
def characters(string)
|
57
24
|
check_latches_and_passthrough(:characters, string)
|
58
25
|
end
|
59
26
|
|
60
|
-
def
|
61
|
-
|
62
|
-
end
|
63
|
-
|
64
|
-
def warning(string)
|
65
|
-
check_latches_and_passthrough(:warning, string)
|
66
|
-
end
|
67
|
-
|
68
|
-
def error(string)
|
69
|
-
check_latches_and_passthrough(:error, string)
|
70
|
-
end
|
71
|
-
|
72
|
-
def cdata_block(string)
|
73
|
-
check_latches_and_passthrough(:cdata_block, string)
|
27
|
+
def ignore_namespaces?
|
28
|
+
@ignore_namespaces
|
74
29
|
end
|
75
30
|
end
|
76
31
|
end
|