multi_xml 0.0.1 → 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.
Potentially problematic release.
This version of multi_xml might be problematic. Click here for more details.
- data/.gitignore +2 -1
- data/.rspec +2 -0
- data/Gemfile +2 -3
- data/Gemfile.lock +17 -9
- data/README.rdoc +6 -6
- data/Rakefile +6 -16
- data/lib/multi_xml.rb +218 -54
- data/lib/multi_xml/parsers/libxml.rb +79 -0
- data/lib/multi_xml/parsers/nokogiri.rb +79 -0
- data/lib/multi_xml/parsers/rexml.rb +127 -0
- data/lib/multi_xml/version.rb +1 -1
- data/multi_xml.gemspec +5 -6
- data/spec/multi_xml_spec.rb +455 -20
- data/spec/spec_helper.rb +1 -6
- metadata +27 -47
- data/lib/multi_xml/engines/rexml.rb +0 -221
- data/spec/spec.opts +0 -2
data/spec/spec_helper.rb
CHANGED
@@ -1,8 +1,7 @@
|
|
1
1
|
$LOAD_PATH.unshift(File.dirname(__FILE__))
|
2
2
|
$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
|
3
3
|
require 'multi_xml'
|
4
|
-
require '
|
5
|
-
require 'spec/autorun'
|
4
|
+
require 'rspec/core'
|
6
5
|
require 'rubygems'
|
7
6
|
begin
|
8
7
|
require 'bundler'
|
@@ -10,7 +9,3 @@ begin
|
|
10
9
|
rescue LoadError
|
11
10
|
$stderr.puts "Bundler (or a dependency) not available."
|
12
11
|
end
|
13
|
-
|
14
|
-
Spec::Runner.configure do |config|
|
15
|
-
|
16
|
-
end
|
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: multi_xml
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
4
|
+
hash: 27
|
5
5
|
prerelease: false
|
6
6
|
segments:
|
7
7
|
- 0
|
8
|
-
- 0
|
9
8
|
- 1
|
10
|
-
|
9
|
+
- 0
|
10
|
+
version: 0.1.0
|
11
11
|
platform: ruby
|
12
12
|
authors:
|
13
13
|
- Erik Michaels-Ober
|
@@ -15,7 +15,7 @@ autorequire:
|
|
15
15
|
bindir: bin
|
16
16
|
cert_chain: []
|
17
17
|
|
18
|
-
date: 2010-10-
|
18
|
+
date: 2010-10-12 00:00:00 -07:00
|
19
19
|
default_executable:
|
20
20
|
dependencies:
|
21
21
|
- !ruby/object:Gem::Dependency
|
@@ -26,94 +26,73 @@ dependencies:
|
|
26
26
|
requirements:
|
27
27
|
- - ~>
|
28
28
|
- !ruby/object:Gem::Version
|
29
|
-
hash:
|
29
|
+
hash: 15
|
30
30
|
segments:
|
31
31
|
- 1
|
32
32
|
- 0
|
33
|
-
|
34
|
-
version: 1.0.2
|
33
|
+
version: "1.0"
|
35
34
|
type: :development
|
36
35
|
version_requirements: *id001
|
37
|
-
- !ruby/object:Gem::Dependency
|
38
|
-
name: hpricot
|
39
|
-
prerelease: false
|
40
|
-
requirement: &id002 !ruby/object:Gem::Requirement
|
41
|
-
none: false
|
42
|
-
requirements:
|
43
|
-
- - ~>
|
44
|
-
- !ruby/object:Gem::Version
|
45
|
-
hash: 59
|
46
|
-
segments:
|
47
|
-
- 0
|
48
|
-
- 8
|
49
|
-
- 2
|
50
|
-
version: 0.8.2
|
51
|
-
type: :development
|
52
|
-
version_requirements: *id002
|
53
36
|
- !ruby/object:Gem::Dependency
|
54
37
|
name: libxml-ruby
|
55
38
|
prerelease: false
|
56
|
-
requirement: &
|
39
|
+
requirement: &id002 !ruby/object:Gem::Requirement
|
57
40
|
none: false
|
58
41
|
requirements:
|
59
42
|
- - ~>
|
60
43
|
- !ruby/object:Gem::Version
|
61
|
-
hash:
|
44
|
+
hash: 13
|
62
45
|
segments:
|
63
46
|
- 1
|
64
47
|
- 1
|
65
|
-
|
66
|
-
version: 1.1.4
|
48
|
+
version: "1.1"
|
67
49
|
type: :development
|
68
|
-
version_requirements: *
|
50
|
+
version_requirements: *id002
|
69
51
|
- !ruby/object:Gem::Dependency
|
70
52
|
name: nokogiri
|
71
53
|
prerelease: false
|
72
|
-
requirement: &
|
54
|
+
requirement: &id003 !ruby/object:Gem::Requirement
|
73
55
|
none: false
|
74
56
|
requirements:
|
75
57
|
- - ~>
|
76
58
|
- !ruby/object:Gem::Version
|
77
|
-
hash:
|
59
|
+
hash: 7
|
78
60
|
segments:
|
79
61
|
- 1
|
80
62
|
- 4
|
81
|
-
|
82
|
-
version: 1.4.3
|
63
|
+
version: "1.4"
|
83
64
|
type: :development
|
84
|
-
version_requirements: *
|
65
|
+
version_requirements: *id003
|
85
66
|
- !ruby/object:Gem::Dependency
|
86
67
|
name: rake
|
87
68
|
prerelease: false
|
88
|
-
requirement: &
|
69
|
+
requirement: &id004 !ruby/object:Gem::Requirement
|
89
70
|
none: false
|
90
71
|
requirements:
|
91
72
|
- - ~>
|
92
73
|
- !ruby/object:Gem::Version
|
93
|
-
hash:
|
74
|
+
hash: 27
|
94
75
|
segments:
|
95
76
|
- 0
|
96
77
|
- 8
|
97
|
-
|
98
|
-
version: 0.8.7
|
78
|
+
version: "0.8"
|
99
79
|
type: :development
|
100
|
-
version_requirements: *
|
80
|
+
version_requirements: *id004
|
101
81
|
- !ruby/object:Gem::Dependency
|
102
82
|
name: rspec
|
103
83
|
prerelease: false
|
104
|
-
requirement: &
|
84
|
+
requirement: &id005 !ruby/object:Gem::Requirement
|
105
85
|
none: false
|
106
86
|
requirements:
|
107
87
|
- - ~>
|
108
88
|
- !ruby/object:Gem::Version
|
109
|
-
hash:
|
89
|
+
hash: 3
|
110
90
|
segments:
|
111
|
-
-
|
112
|
-
- 3
|
91
|
+
- 2
|
113
92
|
- 0
|
114
|
-
version:
|
93
|
+
version: "2.0"
|
115
94
|
type: :development
|
116
|
-
version_requirements: *
|
95
|
+
version_requirements: *id005
|
117
96
|
description: A gem to provide swappable XML backends utilizing LibXML, Nokogiri, Hpricot, or REXML.
|
118
97
|
email:
|
119
98
|
- sferik@gmail.com
|
@@ -125,17 +104,19 @@ extra_rdoc_files: []
|
|
125
104
|
|
126
105
|
files:
|
127
106
|
- .gitignore
|
107
|
+
- .rspec
|
128
108
|
- Gemfile
|
129
109
|
- Gemfile.lock
|
130
110
|
- LICENSE
|
131
111
|
- README.rdoc
|
132
112
|
- Rakefile
|
133
113
|
- lib/multi_xml.rb
|
134
|
-
- lib/multi_xml/
|
114
|
+
- lib/multi_xml/parsers/libxml.rb
|
115
|
+
- lib/multi_xml/parsers/nokogiri.rb
|
116
|
+
- lib/multi_xml/parsers/rexml.rb
|
135
117
|
- lib/multi_xml/version.rb
|
136
118
|
- multi_xml.gemspec
|
137
119
|
- spec/multi_xml_spec.rb
|
138
|
-
- spec/spec.opts
|
139
120
|
- spec/spec_helper.rb
|
140
121
|
has_rdoc: true
|
141
122
|
homepage: http://rubygems.org/gems/multi_xml
|
@@ -173,5 +154,4 @@ specification_version: 3
|
|
173
154
|
summary: A gem to provide swappable XML backends utilizing LibXML, Nokogiri, Hpricot, or REXML.
|
174
155
|
test_files:
|
175
156
|
- spec/multi_xml_spec.rb
|
176
|
-
- spec/spec.opts
|
177
157
|
- spec/spec_helper.rb
|
@@ -1,221 +0,0 @@
|
|
1
|
-
require 'rexml/parsers/baseparser'
|
2
|
-
require 'rexml/text'
|
3
|
-
require 'date'
|
4
|
-
require 'time'
|
5
|
-
require 'yaml'
|
6
|
-
require 'bigdecimal'
|
7
|
-
|
8
|
-
module MultiXml
|
9
|
-
module Engines
|
10
|
-
# Use REXML to parse XML.
|
11
|
-
class Rexml
|
12
|
-
|
13
|
-
def self.parse(string, options = {}) #:nodoc:
|
14
|
-
string.strip!
|
15
|
-
stack = []
|
16
|
-
parser = ::REXML::Parsers::BaseParser.new(string)
|
17
|
-
|
18
|
-
while true
|
19
|
-
event = parser.pull
|
20
|
-
case event[0]
|
21
|
-
when :end_document
|
22
|
-
break
|
23
|
-
when :start_element
|
24
|
-
stack.push RexmlUtilityNode.new(event[1], event[2])
|
25
|
-
when :end_element
|
26
|
-
if stack.size > 1
|
27
|
-
temp = stack.pop
|
28
|
-
stack.last.add_node(temp)
|
29
|
-
end
|
30
|
-
when :text, :cdata
|
31
|
-
stack.last.add_node(event[1]) unless event[1].strip.length == 0 || stack.empty?
|
32
|
-
end
|
33
|
-
end
|
34
|
-
hash = (stack.length > 0 ? stack.pop.to_hash : {})
|
35
|
-
options[:symbolize_keys] ? symbolize_keys(hash) : hash
|
36
|
-
end
|
37
|
-
|
38
|
-
def self.symbolize_keys(hash) #:nodoc:
|
39
|
-
hash.inject({}){|result, (key, value)|
|
40
|
-
new_key = case key
|
41
|
-
when String then key.to_sym
|
42
|
-
else key
|
43
|
-
end
|
44
|
-
new_value = case value
|
45
|
-
when Hash then symbolize_keys(value)
|
46
|
-
else value
|
47
|
-
end
|
48
|
-
result[new_key] = new_value
|
49
|
-
result
|
50
|
-
}
|
51
|
-
end
|
52
|
-
end
|
53
|
-
|
54
|
-
class RexmlUtilityNode #:nodoc:
|
55
|
-
attr_accessor :name, :attributes, :children, :type
|
56
|
-
|
57
|
-
def self.typecasts
|
58
|
-
@@typecasts
|
59
|
-
end
|
60
|
-
|
61
|
-
def self.typecasts=(obj)
|
62
|
-
@@typecasts = obj
|
63
|
-
end
|
64
|
-
|
65
|
-
def self.available_typecasts
|
66
|
-
@@available_typecasts
|
67
|
-
end
|
68
|
-
|
69
|
-
def self.available_typecasts=(obj)
|
70
|
-
@@available_typecasts = obj
|
71
|
-
end
|
72
|
-
|
73
|
-
self.typecasts = {}
|
74
|
-
self.typecasts["integer"] = lambda{|v| v.nil? ? nil : v.to_i}
|
75
|
-
self.typecasts["boolean"] = lambda{|v| v.nil? ? nil : (v.strip != "false")}
|
76
|
-
self.typecasts["datetime"] = lambda{|v| v.nil? ? nil : Time.parse(v).utc}
|
77
|
-
self.typecasts["date"] = lambda{|v| v.nil? ? nil : Date.parse(v)}
|
78
|
-
self.typecasts["dateTime"] = lambda{|v| v.nil? ? nil : Time.parse(v).utc}
|
79
|
-
self.typecasts["decimal"] = lambda{|v| v.nil? ? nil : BigDecimal(v.to_s)}
|
80
|
-
self.typecasts["double"] = lambda{|v| v.nil? ? nil : v.to_f}
|
81
|
-
self.typecasts["float"] = lambda{|v| v.nil? ? nil : v.to_f}
|
82
|
-
self.typecasts["symbol"] = lambda{|v| v.nil? ? nil : v.to_sym}
|
83
|
-
self.typecasts["string"] = lambda{|v| v.to_s}
|
84
|
-
self.typecasts["yaml"] = lambda{|v| v.nil? ? nil : YAML.load(v)}
|
85
|
-
self.typecasts["base64Binary"] = lambda{|v| v.unpack('m').first }
|
86
|
-
|
87
|
-
self.available_typecasts = self.typecasts.keys
|
88
|
-
|
89
|
-
def initialize(name, normalized_attributes = {})
|
90
|
-
|
91
|
-
# unnormalize attribute values
|
92
|
-
attributes = Hash[* normalized_attributes.map { |key, value|
|
93
|
-
[ key, unnormalize_xml_entities(value) ]
|
94
|
-
}.flatten]
|
95
|
-
|
96
|
-
@name = name.tr("-", "_")
|
97
|
-
# leave the type alone if we don't know what it is
|
98
|
-
@type = self.class.available_typecasts.include?(attributes["type"]) ? attributes.delete("type") : attributes["type"]
|
99
|
-
|
100
|
-
@nil_element = attributes.delete("nil") == "true"
|
101
|
-
@attributes = undasherize_keys(attributes)
|
102
|
-
@children = []
|
103
|
-
@text = false
|
104
|
-
end
|
105
|
-
|
106
|
-
def add_node(node)
|
107
|
-
@text = true if node.is_a? String
|
108
|
-
@children << node
|
109
|
-
end
|
110
|
-
|
111
|
-
def to_hash
|
112
|
-
if @type == "file"
|
113
|
-
f = StringIO.new((@children.first || '').unpack('m').first)
|
114
|
-
class << f
|
115
|
-
attr_accessor :original_filename, :content_type
|
116
|
-
end
|
117
|
-
f.original_filename = attributes['name'] || 'untitled'
|
118
|
-
f.content_type = attributes['content_type'] || 'application/octet-stream'
|
119
|
-
return {name => f}
|
120
|
-
end
|
121
|
-
|
122
|
-
if @text
|
123
|
-
t = typecast_value( unnormalize_xml_entities( inner_html ) )
|
124
|
-
t.class.send(:attr_accessor, :attributes)
|
125
|
-
t.attributes = attributes
|
126
|
-
return { name => t }
|
127
|
-
else
|
128
|
-
#change repeating groups into an array
|
129
|
-
groups = @children.inject({}) { |s,e| (s[e.name] ||= []) << e; s }
|
130
|
-
|
131
|
-
out = nil
|
132
|
-
if @type == "array"
|
133
|
-
out = []
|
134
|
-
groups.each do |k, v|
|
135
|
-
if v.size == 1
|
136
|
-
out << v.first.to_hash.entries.first.last
|
137
|
-
else
|
138
|
-
out << v.map{|e| e.to_hash[k]}
|
139
|
-
end
|
140
|
-
end
|
141
|
-
out = out.flatten
|
142
|
-
|
143
|
-
else # If Hash
|
144
|
-
out = {}
|
145
|
-
groups.each do |k,v|
|
146
|
-
if v.size == 1
|
147
|
-
out.merge!(v.first)
|
148
|
-
else
|
149
|
-
out.merge!( k => v.map{|e| e.to_hash[k]})
|
150
|
-
end
|
151
|
-
end
|
152
|
-
out.merge! attributes unless attributes.empty?
|
153
|
-
out = out.empty? ? nil : out
|
154
|
-
end
|
155
|
-
|
156
|
-
if @type && out.nil?
|
157
|
-
{ name => typecast_value(out) }
|
158
|
-
else
|
159
|
-
{ name => out }
|
160
|
-
end
|
161
|
-
end
|
162
|
-
end
|
163
|
-
|
164
|
-
# Typecasts a value based upon its type. For instance, if
|
165
|
-
# +node+ has #type == "integer",
|
166
|
-
# {{[node.typecast_value("12") #=> 12]}}
|
167
|
-
#
|
168
|
-
# @param value<String> The value that is being typecast.
|
169
|
-
#
|
170
|
-
# @details [:type options]
|
171
|
-
# "integer"::
|
172
|
-
# converts +value+ to an integer with #to_i
|
173
|
-
# "boolean"::
|
174
|
-
# checks whether +value+, after removing spaces, is the literal
|
175
|
-
# "true"
|
176
|
-
# "datetime"::
|
177
|
-
# Parses +value+ using Time.parse, and returns a UTC Time
|
178
|
-
# "date"::
|
179
|
-
# Parses +value+ using Date.parse
|
180
|
-
#
|
181
|
-
# @return <Integer, TrueClass, FalseClass, Time, Date, Object>
|
182
|
-
# The result of typecasting +value+.
|
183
|
-
#
|
184
|
-
# @note
|
185
|
-
# If +self+ does not have a "type" key, or if it's not one of the
|
186
|
-
# options specified above, the raw +value+ will be returned.
|
187
|
-
def typecast_value(value)
|
188
|
-
return value unless @type
|
189
|
-
proc = self.class.typecasts[@type]
|
190
|
-
proc.nil? ? value : proc.call(value)
|
191
|
-
end
|
192
|
-
|
193
|
-
# Take keys of the form foo-bar and convert them to foo_bar
|
194
|
-
def undasherize_keys(params)
|
195
|
-
params.keys.each do |key, value|
|
196
|
-
params[key.tr("-", "_")] = params.delete(key)
|
197
|
-
end
|
198
|
-
params
|
199
|
-
end
|
200
|
-
|
201
|
-
# Get the inner_html of the REXML node.
|
202
|
-
def inner_html
|
203
|
-
@children.join
|
204
|
-
end
|
205
|
-
|
206
|
-
# Converts the node into a readable HTML node.
|
207
|
-
#
|
208
|
-
# @return <String> The HTML node in text form.
|
209
|
-
def to_html
|
210
|
-
attributes.merge!(:type => @type ) if @type
|
211
|
-
"<#{name}#{attributes.to_xml_attributes}>#{@nil_element ? '' : inner_html}</#{name}>"
|
212
|
-
end
|
213
|
-
alias :to_s :to_html
|
214
|
-
|
215
|
-
def unnormalize_xml_entities value
|
216
|
-
::REXML::Text.unnormalize(value)
|
217
|
-
end
|
218
|
-
end
|
219
|
-
|
220
|
-
end
|
221
|
-
end
|
data/spec/spec.opts
DELETED