nori 2.7.1 → 2.9.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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +45 -13
- data/README.md +136 -2
- data/lib/nori/parser/nokogiri.rb +53 -6
- data/lib/nori/parser/rexml.rb +31 -2
- data/lib/nori/string_io_file.rb +2 -0
- data/lib/nori/version.rb +1 -1
- data/lib/nori/xml_utility_node.rb +152 -54
- data/lib/nori.rb +27 -1
- metadata +19 -23
- data/.devcontainer/devcontainer.json +0 -19
- data/.github/dependabot.yml +0 -12
- data/.github/workflows/test.yml +0 -26
- data/.gitignore +0 -8
- data/.rspec +0 -1
- data/Gemfile +0 -6
- data/Rakefile +0 -12
- data/benchmark/benchmark.rb +0 -19
- data/benchmark/soap_response.xml +0 -266
- data/nori.gemspec +0 -29
- data/spec/nori/api_spec.rb +0 -177
- data/spec/nori/core_ext/hash_spec.rb +0 -30
- data/spec/nori/nori_spec.rb +0 -650
- data/spec/nori/string_utils_spec.rb +0 -33
- data/spec/spec_helper.rb +0 -2
|
@@ -92,12 +92,11 @@ class Nori
|
|
|
92
92
|
attributes = Hash[*intermediate]
|
|
93
93
|
end
|
|
94
94
|
|
|
95
|
-
|
|
96
|
-
@type = self.class.available_typecasts.include?(attributes["type"]) ? attributes.delete("type") : attributes["type"]
|
|
95
|
+
@type = bare_type(attributes)
|
|
97
96
|
|
|
98
97
|
@nil_element = false
|
|
99
98
|
attributes.keys.each do |key|
|
|
100
|
-
if result =
|
|
99
|
+
if result = nil_attribute_pattern.match(key)
|
|
101
100
|
@nil_element = attributes.delete(key) == "true"
|
|
102
101
|
attributes.delete("xmlns:#{result[2]}") if result[1]
|
|
103
102
|
end
|
|
@@ -127,59 +126,26 @@ class Nori
|
|
|
127
126
|
@children << node
|
|
128
127
|
end
|
|
129
128
|
|
|
129
|
+
# Converts the node into a hash with the node name as its single key.
|
|
130
|
+
#
|
|
131
|
+
# The value depends on the shape of the node. A node typed as "file"
|
|
132
|
+
# becomes a {StringIOFile}, unless the +:serializable+ profile is enabled.
|
|
133
|
+
# That profile returns plain data only, so a file node folds into text and
|
|
134
|
+
# attributes like any other node and the base64 content is left undecoded.
|
|
135
|
+
# A node with text content becomes a typecast scalar. Every other node
|
|
136
|
+
# folds its children into an array or a hash. Under the +:standards+
|
|
137
|
+
# profile no bare type attribute is honored ({#bare_type}), so file
|
|
138
|
+
# decoding, array folding and typecasting never happen there.
|
|
139
|
+
#
|
|
140
|
+
# @return [Hash{String => Object}] the node name mapped to its value
|
|
130
141
|
def to_hash
|
|
131
|
-
if @type == "file"
|
|
132
|
-
|
|
133
|
-
f.original_filename = attributes['name'] || 'untitled'
|
|
134
|
-
f.content_type = attributes['content_type'] || 'application/octet-stream'
|
|
135
|
-
return { name => f }
|
|
136
|
-
end
|
|
137
|
-
|
|
138
|
-
if @text
|
|
139
|
-
t = typecast_value(inner_html)
|
|
140
|
-
t = advanced_typecasting(t) if t.is_a?(String) && @options[:advanced_typecasting]
|
|
142
|
+
return { name => file_value } if @type == "file" && !@options[:serializable]
|
|
143
|
+
return { name => text_value } if @text
|
|
141
144
|
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
return { name => t }
|
|
148
|
-
else
|
|
149
|
-
#change repeating groups into an array
|
|
150
|
-
groups = @children.inject({}) { |s,e| (s[e.name] ||= []) << e; s }
|
|
151
|
-
|
|
152
|
-
out = nil
|
|
153
|
-
if @type == "array"
|
|
154
|
-
out = []
|
|
155
|
-
groups.each do |k, v|
|
|
156
|
-
if v.size == 1
|
|
157
|
-
out << v.first.to_hash.entries.first.last
|
|
158
|
-
else
|
|
159
|
-
out << v.map{|e| e.to_hash[k]}
|
|
160
|
-
end
|
|
161
|
-
end
|
|
162
|
-
out = out.flatten
|
|
163
|
-
|
|
164
|
-
else # If Hash
|
|
165
|
-
out = {}
|
|
166
|
-
groups.each do |k,v|
|
|
167
|
-
if v.size == 1
|
|
168
|
-
out.merge!(v.first)
|
|
169
|
-
else
|
|
170
|
-
out.merge!( k => v.map{|e| e.to_hash[k]})
|
|
171
|
-
end
|
|
172
|
-
end
|
|
173
|
-
out.merge! prefixed_attributes unless attributes.empty?
|
|
174
|
-
out = out.empty? ? @options[:empty_tag_value] : out
|
|
175
|
-
end
|
|
176
|
-
|
|
177
|
-
if @type && out.nil?
|
|
178
|
-
{ name => typecast_value(out) }
|
|
179
|
-
else
|
|
180
|
-
{ name => out }
|
|
181
|
-
end
|
|
182
|
-
end
|
|
145
|
+
groups = group_children
|
|
146
|
+
value = @type == "array" ? array_value(groups) : hash_value(groups)
|
|
147
|
+
value = typecast_value(value) if @type && value.nil?
|
|
148
|
+
{ name => value }
|
|
183
149
|
end
|
|
184
150
|
|
|
185
151
|
# Typecasts a value based upon its type. For instance, if
|
|
@@ -248,6 +214,138 @@ class Nori
|
|
|
248
214
|
alias to_s to_html
|
|
249
215
|
|
|
250
216
|
private
|
|
217
|
+
|
|
218
|
+
# The value of the bare (un-namespaced) type attribute, or nil under
|
|
219
|
+
# the +:standards+ profile. A recognized type is consumed from the
|
|
220
|
+
# attributes because typecasting replaces it with the value it
|
|
221
|
+
# describes. An unrecognized type stays visible as an ordinary
|
|
222
|
+
# attribute. The bare attribute is a Rails +Hash.from_xml+ convention
|
|
223
|
+
# rather than XML, so the +:standards+ profile never reads it and the
|
|
224
|
+
# attribute passes through as ordinary data.
|
|
225
|
+
#
|
|
226
|
+
# @param attributes [Hash{String => String}] the element's attributes
|
|
227
|
+
# @return [String, nil] the type name, or nil when there is none to honor
|
|
228
|
+
def bare_type(attributes)
|
|
229
|
+
return nil if @options[:standards]
|
|
230
|
+
|
|
231
|
+
if self.class.available_typecasts.include?(attributes["type"])
|
|
232
|
+
attributes.delete("type")
|
|
233
|
+
else
|
|
234
|
+
attributes["type"]
|
|
235
|
+
end
|
|
236
|
+
end
|
|
237
|
+
|
|
238
|
+
# The attribute forms that declare an element nil. The prefixed form
|
|
239
|
+
# is the XML Schema Instance convention (xsi:nil). The bare +nil+ form
|
|
240
|
+
# is a Rails +Hash.from_xml+ convention, so the +:standards+ profile
|
|
241
|
+
# only accepts the prefixed form.
|
|
242
|
+
#
|
|
243
|
+
# @return [Regexp] the pattern, with the prefix in capture group 2
|
|
244
|
+
def nil_attribute_pattern
|
|
245
|
+
@options[:standards] ? /^((.+):)nil$/ : /^((.*):)?nil$/
|
|
246
|
+
end
|
|
247
|
+
|
|
248
|
+
# Decodes the base64 content of a node typed as "file" into a
|
|
249
|
+
# {StringIOFile} carrying the filename and content type attributes.
|
|
250
|
+
def file_value
|
|
251
|
+
file = StringIOFile.new((@children.first || '').unpack('m').first)
|
|
252
|
+
file.original_filename = attributes['name'] || 'untitled'
|
|
253
|
+
file.content_type = attributes['content_type'] || 'application/octet-stream'
|
|
254
|
+
file
|
|
255
|
+
end
|
|
256
|
+
|
|
257
|
+
# Typecasts the text content of the node. String results are wrapped
|
|
258
|
+
# so the node's attributes stay accessible on the value.
|
|
259
|
+
def text_value
|
|
260
|
+
value = typecast_value(inner_html)
|
|
261
|
+
value = advanced_typecasting(value) if value.is_a?(String) && @options[:advanced_typecasting]
|
|
262
|
+
value.is_a?(String) ? string_with_attributes(value) : value
|
|
263
|
+
end
|
|
264
|
+
|
|
265
|
+
# Groups the child nodes by their name so repeating siblings can be
|
|
266
|
+
# folded into arrays.
|
|
267
|
+
#
|
|
268
|
+
# @return [Hash{String => Array<XMLUtilityNode>}]
|
|
269
|
+
def group_children
|
|
270
|
+
@children.inject({}) { |hash, child| (hash[child.name] ||= []) << child; hash }
|
|
271
|
+
end
|
|
272
|
+
|
|
273
|
+
# Collects the values of all child nodes for a node typed as "array".
|
|
274
|
+
def array_value(groups)
|
|
275
|
+
values = []
|
|
276
|
+
groups.each do |child_name, nodes|
|
|
277
|
+
if nodes.size == 1
|
|
278
|
+
values << nodes.first.to_hash.entries.first.last
|
|
279
|
+
else
|
|
280
|
+
values << nodes.map { |node| node.to_hash[child_name] }
|
|
281
|
+
end
|
|
282
|
+
end
|
|
283
|
+
values.flatten
|
|
284
|
+
end
|
|
285
|
+
|
|
286
|
+
# Folds the child nodes and the prefixed attributes into a hash.
|
|
287
|
+
# An empty result becomes the :empty_tag_value option.
|
|
288
|
+
def hash_value(groups)
|
|
289
|
+
return consistent_empty_value if @options[:consistent_empty_tags] && groups.empty?
|
|
290
|
+
|
|
291
|
+
value = {}
|
|
292
|
+
groups.each do |child_name, nodes|
|
|
293
|
+
if nodes.size == 1
|
|
294
|
+
value.merge!(nodes.first.to_hash)
|
|
295
|
+
else
|
|
296
|
+
value.merge!(child_name => nodes.map { |node| node.to_hash[child_name] })
|
|
297
|
+
end
|
|
298
|
+
end
|
|
299
|
+
value.merge!(prefixed_attributes) unless attributes.empty?
|
|
300
|
+
value.empty? ? @options[:empty_tag_value] : value
|
|
301
|
+
end
|
|
302
|
+
|
|
303
|
+
# Resolves an element without children and without text when the
|
|
304
|
+
# :consistent_empty_tags option is set. The element becomes the
|
|
305
|
+
# :empty_tag_value option no matter which attributes it carries.
|
|
306
|
+
# A string value keeps the attributes accessible on the value.
|
|
307
|
+
# An explicit xsi:nil="true" wins over the option and becomes nil.
|
|
308
|
+
def consistent_empty_value
|
|
309
|
+
return nil if @nil_element
|
|
310
|
+
|
|
311
|
+
value = @options[:empty_tag_value]
|
|
312
|
+
value.is_a?(String) ? string_with_attributes(value) : value
|
|
313
|
+
end
|
|
314
|
+
|
|
315
|
+
# Combines a string +value+ with the node's attributes in the shape the
|
|
316
|
+
# active output profile calls for.
|
|
317
|
+
#
|
|
318
|
+
# By default the value is a {StringWithAttributes}: a String carrying the
|
|
319
|
+
# node's attributes on {StringWithAttributes#attributes}. Under the
|
|
320
|
+
# +:serializable+ profile the value becomes plain, directly-serializable
|
|
321
|
+
# data instead, so no custom String subclass is returned.
|
|
322
|
+
#
|
|
323
|
+
# @param value [String] the typecast text content of the node
|
|
324
|
+
# @return [StringWithAttributes, Hash{String => String}, String] the value
|
|
325
|
+
# in the configured representation
|
|
326
|
+
def string_with_attributes(value)
|
|
327
|
+
return serializable_value(value) if @options[:serializable]
|
|
328
|
+
|
|
329
|
+
string = StringWithAttributes.new(value)
|
|
330
|
+
string.attributes = attributes
|
|
331
|
+
string
|
|
332
|
+
end
|
|
333
|
+
|
|
334
|
+
# The +:serializable+ representation of a string +value+ and the node's
|
|
335
|
+
# attributes. A node with attributes maps to the XML JSON convention
|
|
336
|
+
# (+{"#text" => value}+ merged with the "@"-prefixed attributes) and a
|
|
337
|
+
# node without attributes maps to the plain String. The attribute keys go
|
|
338
|
+
# through the same prefixing and tag conversion as element-node attributes
|
|
339
|
+
# ({#prefixed_attributes}), so every node kind shares one convention.
|
|
340
|
+
#
|
|
341
|
+
# @param value [String] the typecast text content of the node
|
|
342
|
+
# @return [Hash{String => String}, String] the hash shape when the node
|
|
343
|
+
# has attributes, otherwise the plain +value+
|
|
344
|
+
def serializable_value(value)
|
|
345
|
+
return value if attributes.empty?
|
|
346
|
+
{ "#text" => value }.merge(prefixed_attributes)
|
|
347
|
+
end
|
|
348
|
+
|
|
251
349
|
def try_to_convert(value, &block)
|
|
252
350
|
block.call(value)
|
|
253
351
|
rescue ArgumentError
|
data/lib/nori.rb
CHANGED
|
@@ -20,14 +20,17 @@ class Nori
|
|
|
20
20
|
:convert_tags_to => nil,
|
|
21
21
|
:convert_attributes_to => nil,
|
|
22
22
|
:empty_tag_value => nil,
|
|
23
|
+
:consistent_empty_tags => false,
|
|
23
24
|
:advanced_typecasting => true,
|
|
24
25
|
:convert_dashes_to_underscores => true,
|
|
25
26
|
:scrub_xml => true,
|
|
27
|
+
:standards => false,
|
|
28
|
+
:serializable => false,
|
|
26
29
|
:parser => :nokogiri
|
|
27
30
|
}
|
|
28
31
|
|
|
29
32
|
validate_options! defaults.keys, options.keys
|
|
30
|
-
@options = defaults.merge(options)
|
|
33
|
+
@options = defaults.merge(standards_defaults(options)).merge(options)
|
|
31
34
|
end
|
|
32
35
|
|
|
33
36
|
def find(hash, *path)
|
|
@@ -49,6 +52,29 @@ class Nori
|
|
|
49
52
|
end
|
|
50
53
|
|
|
51
54
|
private
|
|
55
|
+
|
|
56
|
+
# The defaults implied by the +:standards+ profile.
|
|
57
|
+
#
|
|
58
|
+
# The profile groups the spec-correct behaviors under a single opt-in.
|
|
59
|
+
# It turns on the XML string-value model for empty elements
|
|
60
|
+
# (+:consistent_empty_tags+ with an empty-string +:empty_tag_value+),
|
|
61
|
+
# turns off +:advanced_typecasting+ (schema-less values are text, their
|
|
62
|
+
# types are the business of a schema-aware layer) and, in the parsers,
|
|
63
|
+
# honors xml:space. These are defaults, so an explicit option passed by
|
|
64
|
+
# the caller still wins. When the profile is off the hash is empty and
|
|
65
|
+
# parsing is unchanged.
|
|
66
|
+
#
|
|
67
|
+
# @param options [Hash] the options passed to {#initialize}
|
|
68
|
+
# @return [Hash] the implied defaults, or +{}+ when the profile is off
|
|
69
|
+
def standards_defaults(options)
|
|
70
|
+
return {} unless options[:standards]
|
|
71
|
+
{
|
|
72
|
+
:consistent_empty_tags => true,
|
|
73
|
+
:empty_tag_value => "",
|
|
74
|
+
:advanced_typecasting => false
|
|
75
|
+
}
|
|
76
|
+
end
|
|
77
|
+
|
|
52
78
|
def load_parser(parser)
|
|
53
79
|
require "nori/parser/#{parser}"
|
|
54
80
|
Parser.const_get PARSERS[parser]
|
metadata
CHANGED
|
@@ -1,16 +1,15 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: nori
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 2.
|
|
4
|
+
version: 2.9.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Daniel Harrington
|
|
8
8
|
- John Nunemaker
|
|
9
9
|
- Wynn Netherland
|
|
10
|
-
autorequire:
|
|
11
10
|
bindir: bin
|
|
12
11
|
cert_chain: []
|
|
13
|
-
date:
|
|
12
|
+
date: 1980-01-02 00:00:00.000000000 Z
|
|
14
13
|
dependencies:
|
|
15
14
|
- !ruby/object:Gem::Dependency
|
|
16
15
|
name: bigdecimal
|
|
@@ -26,20 +25,34 @@ dependencies:
|
|
|
26
25
|
- - ">="
|
|
27
26
|
- !ruby/object:Gem::Version
|
|
28
27
|
version: '0'
|
|
28
|
+
- !ruby/object:Gem::Dependency
|
|
29
|
+
name: stringio
|
|
30
|
+
requirement: !ruby/object:Gem::Requirement
|
|
31
|
+
requirements:
|
|
32
|
+
- - ">="
|
|
33
|
+
- !ruby/object:Gem::Version
|
|
34
|
+
version: '0'
|
|
35
|
+
type: :runtime
|
|
36
|
+
prerelease: false
|
|
37
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
38
|
+
requirements:
|
|
39
|
+
- - ">="
|
|
40
|
+
- !ruby/object:Gem::Version
|
|
41
|
+
version: '0'
|
|
29
42
|
- !ruby/object:Gem::Dependency
|
|
30
43
|
name: rake
|
|
31
44
|
requirement: !ruby/object:Gem::Requirement
|
|
32
45
|
requirements:
|
|
33
46
|
- - "~>"
|
|
34
47
|
- !ruby/object:Gem::Version
|
|
35
|
-
version:
|
|
48
|
+
version: '13.3'
|
|
36
49
|
type: :development
|
|
37
50
|
prerelease: false
|
|
38
51
|
version_requirements: !ruby/object:Gem::Requirement
|
|
39
52
|
requirements:
|
|
40
53
|
- - "~>"
|
|
41
54
|
- !ruby/object:Gem::Version
|
|
42
|
-
version:
|
|
55
|
+
version: '13.3'
|
|
43
56
|
- !ruby/object:Gem::Dependency
|
|
44
57
|
name: nokogiri
|
|
45
58
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -74,18 +87,9 @@ executables: []
|
|
|
74
87
|
extensions: []
|
|
75
88
|
extra_rdoc_files: []
|
|
76
89
|
files:
|
|
77
|
-
- ".devcontainer/devcontainer.json"
|
|
78
|
-
- ".github/dependabot.yml"
|
|
79
|
-
- ".github/workflows/test.yml"
|
|
80
|
-
- ".gitignore"
|
|
81
|
-
- ".rspec"
|
|
82
90
|
- CHANGELOG.md
|
|
83
|
-
- Gemfile
|
|
84
91
|
- LICENSE
|
|
85
92
|
- README.md
|
|
86
|
-
- Rakefile
|
|
87
|
-
- benchmark/benchmark.rb
|
|
88
|
-
- benchmark/soap_response.xml
|
|
89
93
|
- lib/nori.rb
|
|
90
94
|
- lib/nori/core_ext.rb
|
|
91
95
|
- lib/nori/core_ext/hash.rb
|
|
@@ -96,18 +100,11 @@ files:
|
|
|
96
100
|
- lib/nori/string_with_attributes.rb
|
|
97
101
|
- lib/nori/version.rb
|
|
98
102
|
- lib/nori/xml_utility_node.rb
|
|
99
|
-
- nori.gemspec
|
|
100
|
-
- spec/nori/api_spec.rb
|
|
101
|
-
- spec/nori/core_ext/hash_spec.rb
|
|
102
|
-
- spec/nori/nori_spec.rb
|
|
103
|
-
- spec/nori/string_utils_spec.rb
|
|
104
|
-
- spec/spec_helper.rb
|
|
105
103
|
homepage: https://github.com/savonrb/nori
|
|
106
104
|
licenses:
|
|
107
105
|
- MIT
|
|
108
106
|
metadata:
|
|
109
107
|
rubygems_mfa_required: 'true'
|
|
110
|
-
post_install_message:
|
|
111
108
|
rdoc_options: []
|
|
112
109
|
require_paths:
|
|
113
110
|
- lib
|
|
@@ -122,8 +119,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
122
119
|
- !ruby/object:Gem::Version
|
|
123
120
|
version: '0'
|
|
124
121
|
requirements: []
|
|
125
|
-
rubygems_version: 3.
|
|
126
|
-
signing_key:
|
|
122
|
+
rubygems_version: 3.6.9
|
|
127
123
|
specification_version: 4
|
|
128
124
|
summary: XML to Hash translator
|
|
129
125
|
test_files: []
|
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
// For format details, see https://aka.ms/devcontainer.json. For config options, see the
|
|
2
|
-
// README at: https://github.com/devcontainers/templates/tree/main/src/ruby
|
|
3
|
-
{
|
|
4
|
-
"name": "Ruby",
|
|
5
|
-
// Or use a Dockerfile or Docker Compose file. More info: https://containers.dev/guide/dockerfile
|
|
6
|
-
"image": "mcr.microsoft.com/devcontainers/ruby:0-3-bullseye"
|
|
7
|
-
|
|
8
|
-
// Features to add to the dev container. More info: https://containers.dev/features.
|
|
9
|
-
// "features": {},
|
|
10
|
-
|
|
11
|
-
// Use 'forwardPorts' to make a list of ports inside the container available locally.
|
|
12
|
-
// "forwardPorts": [],
|
|
13
|
-
|
|
14
|
-
// Configure tool-specific properties.
|
|
15
|
-
// "customizations": {},
|
|
16
|
-
|
|
17
|
-
// Uncomment to connect as root instead. More info: https://aka.ms/dev-containers-non-root.
|
|
18
|
-
// "remoteUser": "root"
|
|
19
|
-
}
|
data/.github/dependabot.yml
DELETED
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
# To get started with Dependabot version updates, you'll need to specify which
|
|
2
|
-
# package ecosystems to update and where the package manifests are located.
|
|
3
|
-
# Please see the documentation for more information:
|
|
4
|
-
# https://docs.github.com/github/administering-a-repository/configuration-options-for-dependency-updates
|
|
5
|
-
# https://containers.dev/guide/dependabot
|
|
6
|
-
|
|
7
|
-
version: 2
|
|
8
|
-
updates:
|
|
9
|
-
- package-ecosystem: "devcontainers"
|
|
10
|
-
directory: "/"
|
|
11
|
-
schedule:
|
|
12
|
-
interval: weekly
|
data/.github/workflows/test.yml
DELETED
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
name: CI
|
|
2
|
-
|
|
3
|
-
on: [push, pull_request]
|
|
4
|
-
|
|
5
|
-
jobs:
|
|
6
|
-
build:
|
|
7
|
-
runs-on: ubuntu-latest
|
|
8
|
-
|
|
9
|
-
strategy:
|
|
10
|
-
matrix:
|
|
11
|
-
ruby-version:
|
|
12
|
-
- '3.0'
|
|
13
|
-
- '3.1'
|
|
14
|
-
- '3.2'
|
|
15
|
-
- '3.3'
|
|
16
|
-
- 'head'
|
|
17
|
-
- jruby-9.4.5.0
|
|
18
|
-
steps:
|
|
19
|
-
- uses: actions/checkout@v4
|
|
20
|
-
- name: Set up Ruby ${{ matrix.ruby-version }}
|
|
21
|
-
uses: ruby/setup-ruby@v1
|
|
22
|
-
with:
|
|
23
|
-
ruby-version: ${{ matrix.ruby-version }}
|
|
24
|
-
bundler-cache: true # runs 'bundle install' and caches installed gems automatically
|
|
25
|
-
- name: Run tests
|
|
26
|
-
run: bundle exec rake
|
data/.gitignore
DELETED
data/.rspec
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
--colour
|
data/Gemfile
DELETED
data/Rakefile
DELETED
data/benchmark/benchmark.rb
DELETED
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
$:.push File.expand_path("../../lib", __FILE__)
|
|
2
|
-
require "nori"
|
|
3
|
-
|
|
4
|
-
require "benchmark"
|
|
5
|
-
|
|
6
|
-
Benchmark.bm 30 do |x|
|
|
7
|
-
|
|
8
|
-
num = 500
|
|
9
|
-
xml = File.read File.expand_path("../soap_response.xml", __FILE__)
|
|
10
|
-
|
|
11
|
-
x.report "rexml parser" do
|
|
12
|
-
num.times { Nori.new(parser: :rexml).parse xml }
|
|
13
|
-
end
|
|
14
|
-
|
|
15
|
-
x.report "nokogiri parser" do
|
|
16
|
-
num.times { Nori.new(parser: :nokogiri).parse xml }
|
|
17
|
-
end
|
|
18
|
-
|
|
19
|
-
end
|