aliyun-oss-ex 0.7.0.1402831795
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 +7 -0
- data/COPYING +19 -0
- data/INSTALL +35 -0
- data/README +443 -0
- data/Rakefile +334 -0
- data/bin/oss +6 -0
- data/bin/setup.rb +11 -0
- data/lib/aliyun/oss.rb +55 -0
- data/lib/aliyun/oss/acl.rb +132 -0
- data/lib/aliyun/oss/authentication.rb +222 -0
- data/lib/aliyun/oss/base.rb +241 -0
- data/lib/aliyun/oss/bucket.rb +320 -0
- data/lib/aliyun/oss/connection.rb +279 -0
- data/lib/aliyun/oss/error.rb +70 -0
- data/lib/aliyun/oss/exceptions.rb +134 -0
- data/lib/aliyun/oss/extensions.rb +405 -0
- data/lib/aliyun/oss/logging.rb +304 -0
- data/lib/aliyun/oss/object.rb +612 -0
- data/lib/aliyun/oss/owner.rb +45 -0
- data/lib/aliyun/oss/parsing.rb +100 -0
- data/lib/aliyun/oss/response.rb +181 -0
- data/lib/aliyun/oss/service.rb +52 -0
- data/lib/aliyun/oss/version.rb +14 -0
- data/support/faster-xml-simple/lib/faster_xml_simple.rb +188 -0
- data/support/faster-xml-simple/test/regression_test.rb +48 -0
- data/support/faster-xml-simple/test/test_helper.rb +18 -0
- data/support/faster-xml-simple/test/xml_simple_comparison_test.rb +47 -0
- data/support/rdoc/code_info.rb +212 -0
- data/test/acl_test.rb +70 -0
- data/test/authentication_test.rb +114 -0
- data/test/base_test.rb +137 -0
- data/test/bucket_test.rb +75 -0
- data/test/connection_test.rb +218 -0
- data/test/error_test.rb +71 -0
- data/test/extensions_test.rb +346 -0
- data/test/fixtures.rb +90 -0
- data/test/fixtures/buckets.yml +133 -0
- data/test/fixtures/errors.yml +34 -0
- data/test/fixtures/headers.yml +3 -0
- data/test/fixtures/logging.yml +15 -0
- data/test/fixtures/loglines.yml +5 -0
- data/test/fixtures/logs.yml +7 -0
- data/test/fixtures/policies.yml +16 -0
- data/test/logging_test.rb +90 -0
- data/test/mocks/fake_response.rb +27 -0
- data/test/object_test.rb +221 -0
- data/test/parsing_test.rb +67 -0
- data/test/remote/acl_test.rb +28 -0
- data/test/remote/bucket_test.rb +147 -0
- data/test/remote/logging_test.rb +86 -0
- data/test/remote/object_test.rb +350 -0
- data/test/remote/test_file.data +0 -0
- data/test/remote/test_helper.rb +34 -0
- data/test/response_test.rb +69 -0
- data/test/service_test.rb +24 -0
- data/test/test_helper.rb +110 -0
- metadata +177 -0
@@ -0,0 +1,45 @@
|
|
1
|
+
# -*- encoding : utf-8 -*-
|
2
|
+
module Aliyun
|
3
|
+
module OSS
|
4
|
+
# Entities in OSS have an associated owner (the person who created them). The owner is a canonical representation of an
|
5
|
+
# entity in the OSS system. It has an <tt>id</tt> and a <tt>display_name</tt>.
|
6
|
+
#
|
7
|
+
# These attributes can be used when specifying a ACL::Grantee for an ACL::Grant.
|
8
|
+
#
|
9
|
+
# You can retrieve the owner of the current account by calling Owner.current.
|
10
|
+
class Owner
|
11
|
+
undef_method :id if method_defined?(:id) # Get rid of Object#id
|
12
|
+
include SelectiveAttributeProxy
|
13
|
+
|
14
|
+
class << self
|
15
|
+
# The owner of the current account.
|
16
|
+
def current
|
17
|
+
response = Service.get('/')
|
18
|
+
new(response.parsed['owner']) if response.parsed['owner']
|
19
|
+
end
|
20
|
+
memoized :current
|
21
|
+
end
|
22
|
+
|
23
|
+
def initialize(attributes = {}) #:nodoc:
|
24
|
+
@attributes = attributes
|
25
|
+
end
|
26
|
+
|
27
|
+
def ==(other_owner) #:nodoc:
|
28
|
+
hash == other_owner.hash
|
29
|
+
end
|
30
|
+
|
31
|
+
def hash #:nodoc
|
32
|
+
[id, display_name].join.hash
|
33
|
+
end
|
34
|
+
|
35
|
+
private
|
36
|
+
def proxiable_attribute?(name)
|
37
|
+
valid_attributes.include?(name)
|
38
|
+
end
|
39
|
+
|
40
|
+
def valid_attributes
|
41
|
+
%w(id display_name)
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
@@ -0,0 +1,100 @@
|
|
1
|
+
# -*- encoding : utf-8 -*-
|
2
|
+
#:stopdoc:
|
3
|
+
module Aliyun
|
4
|
+
module OSS
|
5
|
+
module Parsing
|
6
|
+
class << self
|
7
|
+
def parser=(parsing_library)
|
8
|
+
XmlParser.parsing_library = parsing_library
|
9
|
+
end
|
10
|
+
|
11
|
+
def parser
|
12
|
+
XmlParser.parsing_library
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
module Typecasting
|
17
|
+
def typecast(object)
|
18
|
+
case object
|
19
|
+
when Hash
|
20
|
+
typecast_hash(object)
|
21
|
+
when Array
|
22
|
+
object.map {|element| typecast(element)}
|
23
|
+
when String
|
24
|
+
CoercibleString.coerce(object)
|
25
|
+
else
|
26
|
+
object
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
def typecast_hash(hash)
|
31
|
+
if content = hash['__content__']
|
32
|
+
typecast(content)
|
33
|
+
else
|
34
|
+
keys = hash.keys.map {|key| key.underscore}
|
35
|
+
values = hash.values.map {|value| typecast(value)}
|
36
|
+
keys.inject({}) do |new_hash, key|
|
37
|
+
new_hash[key] = values.slice!(0)
|
38
|
+
new_hash
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
class XmlParser < Hash
|
45
|
+
include Typecasting
|
46
|
+
|
47
|
+
class << self
|
48
|
+
attr_accessor :parsing_library
|
49
|
+
end
|
50
|
+
|
51
|
+
attr_reader :body, :xml_in, :root
|
52
|
+
|
53
|
+
def initialize(body)
|
54
|
+
@body = body
|
55
|
+
unless body.strip.empty?
|
56
|
+
parse
|
57
|
+
set_root
|
58
|
+
typecast_xml_in
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
private
|
63
|
+
|
64
|
+
def parse
|
65
|
+
@xml_in = self.class.parsing_library.xml_in(body, parsing_options)
|
66
|
+
end
|
67
|
+
|
68
|
+
def parsing_options
|
69
|
+
{
|
70
|
+
# Includes the enclosing tag as the top level key
|
71
|
+
'keeproot' => true,
|
72
|
+
# Makes tag value available via the '__content__' key
|
73
|
+
'contentkey' => '__content__',
|
74
|
+
# Always parse tags into a hash, even when there are no attributes
|
75
|
+
# (unless there is also no value, in which case it is nil)
|
76
|
+
'forcecontent' => true,
|
77
|
+
# If a tag is empty, makes its content nil
|
78
|
+
'suppressempty' => nil,
|
79
|
+
# Force nested elements to be put into an array, even if there is only one of them
|
80
|
+
'forcearray' => ['Contents', 'Bucket', 'Grant']
|
81
|
+
}
|
82
|
+
end
|
83
|
+
|
84
|
+
def set_root
|
85
|
+
@root = @xml_in.keys.first.underscore
|
86
|
+
end
|
87
|
+
|
88
|
+
def typecast_xml_in
|
89
|
+
typecast_xml = {}
|
90
|
+
@xml_in.dup.each do |key, value| # Some typecasting is destructive so we dup
|
91
|
+
typecast_xml[key.underscore] = typecast(value)
|
92
|
+
end
|
93
|
+
# An empty body will try to update with a string so only update if the result is a hash
|
94
|
+
update(typecast_xml[root]) if typecast_xml[root].is_a?(Hash)
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|
99
|
+
end
|
100
|
+
#:startdoc:
|
@@ -0,0 +1,181 @@
|
|
1
|
+
# -*- encoding : utf-8 -*-
|
2
|
+
#:stopdoc:
|
3
|
+
module Aliyun
|
4
|
+
module OSS
|
5
|
+
class Base
|
6
|
+
class Response < String
|
7
|
+
attr_reader :response, :body, :parsed
|
8
|
+
def initialize(response)
|
9
|
+
@response = response
|
10
|
+
@body = response.body.to_s
|
11
|
+
super(body)
|
12
|
+
end
|
13
|
+
|
14
|
+
def headers
|
15
|
+
headers = {}
|
16
|
+
response.each do |header, value|
|
17
|
+
headers[header] = value
|
18
|
+
end
|
19
|
+
headers
|
20
|
+
end
|
21
|
+
memoized :headers
|
22
|
+
|
23
|
+
def [](header)
|
24
|
+
headers[header]
|
25
|
+
end
|
26
|
+
|
27
|
+
def each(&block)
|
28
|
+
headers.each(&block)
|
29
|
+
end
|
30
|
+
|
31
|
+
def code
|
32
|
+
response.code.to_i
|
33
|
+
end
|
34
|
+
|
35
|
+
{:success => 200..299, :redirect => 300..399,
|
36
|
+
:client_error => 400..499, :server_error => 500..599}.each do |result, code_range|
|
37
|
+
class_eval(<<-EVAL, __FILE__, __LINE__)
|
38
|
+
def #{result}?
|
39
|
+
return false unless response
|
40
|
+
(#{code_range}).include? code
|
41
|
+
end
|
42
|
+
EVAL
|
43
|
+
end
|
44
|
+
|
45
|
+
def error?
|
46
|
+
!success? && response['content-type'] == 'application/xml' && parsed.root == 'error'
|
47
|
+
end
|
48
|
+
|
49
|
+
def error
|
50
|
+
Error.new(parsed, self)
|
51
|
+
end
|
52
|
+
memoized :error
|
53
|
+
|
54
|
+
def parsed
|
55
|
+
# XmlSimple is picky about what kind of object it parses, so we pass in body rather than self
|
56
|
+
Parsing::XmlParser.new(body)
|
57
|
+
end
|
58
|
+
memoized :parsed
|
59
|
+
|
60
|
+
def inspect
|
61
|
+
"#<%s:0x%s %s %s>" % [self.class, object_id, response.code, response.message]
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
class Bucket
|
67
|
+
class Response < Base::Response
|
68
|
+
def bucket
|
69
|
+
parsed
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
class OSSObject
|
75
|
+
class Response < Base::Response
|
76
|
+
def etag
|
77
|
+
headers['etag'][1...-1]
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
class Service
|
83
|
+
class Response < Base::Response
|
84
|
+
def empty?
|
85
|
+
parsed['buckets'].nil?
|
86
|
+
end
|
87
|
+
|
88
|
+
def buckets
|
89
|
+
parsed['buckets']['bucket'] || []
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
module ACL
|
95
|
+
class Policy
|
96
|
+
class Response < Base::Response
|
97
|
+
alias_method :policy, :parsed
|
98
|
+
end
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
# Requests whose response code is between 300 and 599 and contain an <Error></Error> in their body
|
103
|
+
# are wrapped in an Error::Response. This Error::Response contains an Error object which raises an exception
|
104
|
+
# that corresponds to the error in the response body. The exception object contains the ErrorResponse, so
|
105
|
+
# in all cases where a request happens, you can rescue ResponseError and have access to the ErrorResponse and
|
106
|
+
# its Error object which contains information about the ResponseError.
|
107
|
+
#
|
108
|
+
# begin
|
109
|
+
# Bucket.create(..)
|
110
|
+
# rescue ResponseError => exception
|
111
|
+
# exception.response
|
112
|
+
# # => <Error::Response>
|
113
|
+
# exception.response.error
|
114
|
+
# # => <Error>
|
115
|
+
# end
|
116
|
+
class Error
|
117
|
+
class Response < Base::Response
|
118
|
+
def error?
|
119
|
+
true
|
120
|
+
end
|
121
|
+
|
122
|
+
def inspect
|
123
|
+
"#<%s:0x%s %s %s: '%s'>" % [self.class.name, object_id, response.code, error.code, error.message]
|
124
|
+
end
|
125
|
+
end
|
126
|
+
end
|
127
|
+
|
128
|
+
# Guess response class name from current class name. If the guessed response class doesn't exist
|
129
|
+
# do the same thing to the current class's parent class, up the inheritance heirarchy until either
|
130
|
+
# a response class is found or until we get to the top of the heirarchy in which case we just use
|
131
|
+
# the the Base response class.
|
132
|
+
#
|
133
|
+
# Important: This implemantation assumes that the Base class has a corresponding Base::Response.
|
134
|
+
class FindResponseClass #:nodoc:
|
135
|
+
class << self
|
136
|
+
def for(start)
|
137
|
+
new(start).find
|
138
|
+
end
|
139
|
+
end
|
140
|
+
|
141
|
+
def initialize(start)
|
142
|
+
@container = Aliyun::OSS
|
143
|
+
@current_class = start
|
144
|
+
end
|
145
|
+
|
146
|
+
def find
|
147
|
+
self.current_class = current_class.superclass until response_class_found?
|
148
|
+
target.const_get(class_to_find)
|
149
|
+
end
|
150
|
+
|
151
|
+
private
|
152
|
+
attr_reader :container
|
153
|
+
attr_accessor :current_class
|
154
|
+
|
155
|
+
def target
|
156
|
+
container.const_get(current_name)
|
157
|
+
end
|
158
|
+
|
159
|
+
def target?
|
160
|
+
container.const_defined?(current_name)
|
161
|
+
end
|
162
|
+
|
163
|
+
def response_class_found?
|
164
|
+
target? && target.const_defined?(class_to_find)
|
165
|
+
end
|
166
|
+
|
167
|
+
def class_to_find
|
168
|
+
:Response
|
169
|
+
end
|
170
|
+
|
171
|
+
def current_name
|
172
|
+
truncate(current_class)
|
173
|
+
end
|
174
|
+
|
175
|
+
def truncate(klass)
|
176
|
+
klass.name[/[^:]+$/]
|
177
|
+
end
|
178
|
+
end
|
179
|
+
end
|
180
|
+
end
|
181
|
+
#:startdoc:
|
@@ -0,0 +1,52 @@
|
|
1
|
+
# -*- encoding : utf-8 -*-
|
2
|
+
module Aliyun
|
3
|
+
module OSS
|
4
|
+
# The service lets you find out general information about your account, like what buckets you have.
|
5
|
+
#
|
6
|
+
# Service.buckets
|
7
|
+
# # => []
|
8
|
+
class Service < Base
|
9
|
+
@@response = nil #:nodoc:
|
10
|
+
|
11
|
+
class << self
|
12
|
+
# List all your buckets.
|
13
|
+
#
|
14
|
+
# Service.buckets
|
15
|
+
# # => []
|
16
|
+
#
|
17
|
+
# For performance reasons, the bucket list will be cached. If you want avoid all caching, pass the <tt>:reload</tt>
|
18
|
+
# as an argument:
|
19
|
+
#
|
20
|
+
# Service.buckets(:reload)
|
21
|
+
def buckets
|
22
|
+
response = get('/')
|
23
|
+
if response.empty?
|
24
|
+
[]
|
25
|
+
else
|
26
|
+
response.buckets.map {|attributes| Bucket.new(attributes)}
|
27
|
+
end
|
28
|
+
end
|
29
|
+
memoized :buckets
|
30
|
+
|
31
|
+
# Sometimes methods that make requests to the OSS servers return some object, like a Bucket or an OSSObject.
|
32
|
+
# Other times they return just <tt>true</tt>. Other times they raise an exception that you may want to rescue. Despite all these
|
33
|
+
# possible outcomes, every method that makes a request stores its response object for you in Service.response. You can always
|
34
|
+
# get to the last request's response via Service.response.
|
35
|
+
#
|
36
|
+
# objects = Bucket.objects('jukebox')
|
37
|
+
# Service.response.success?
|
38
|
+
# # => true
|
39
|
+
#
|
40
|
+
# This is also useful when an error exception is raised in the console which you weren't expecting. You can
|
41
|
+
# root around in the response to get more details of what might have gone wrong.
|
42
|
+
def response
|
43
|
+
@@response
|
44
|
+
end
|
45
|
+
|
46
|
+
def response=(response) #:nodoc:
|
47
|
+
@@response = response
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
# -*- encoding : utf-8 -*-
|
2
|
+
module Aliyun
|
3
|
+
module OSS
|
4
|
+
module VERSION #:nodoc:
|
5
|
+
MAJOR = '0'
|
6
|
+
MINOR = '7'
|
7
|
+
TINY = '0'
|
8
|
+
#BETA = nil # Time.now.to_i.to_s
|
9
|
+
BETA = Time.now.to_i.to_s
|
10
|
+
end
|
11
|
+
|
12
|
+
Version = [VERSION::MAJOR, VERSION::MINOR, VERSION::TINY, VERSION::BETA].compact * '.'
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,188 @@
|
|
1
|
+
# -*- encoding : utf-8 -*-
|
2
|
+
#
|
3
|
+
# Copyright (c) 2006 Michael Koziarski
|
4
|
+
#
|
5
|
+
# Permission is hereby granted, free of charge, to any person obtaining a copy of
|
6
|
+
# this software and associated documentation files (the "Software"), to deal in the
|
7
|
+
# Software without restriction, including without limitation the rights to use,
|
8
|
+
# copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the
|
9
|
+
# Software, and to permit persons to whom the Software is furnished to do so,
|
10
|
+
# subject to the following conditions:
|
11
|
+
#
|
12
|
+
# The above copyright notice and this permission notice shall be included in all
|
13
|
+
# copies or substantial portions of the Software.
|
14
|
+
#
|
15
|
+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
17
|
+
# FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
18
|
+
# COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
|
19
|
+
# AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
21
|
+
|
22
|
+
require 'rubygems'
|
23
|
+
require 'xml/libxml'
|
24
|
+
|
25
|
+
class FasterXmlSimple
|
26
|
+
Version = '0.5.0'
|
27
|
+
class << self
|
28
|
+
# Take an string containing XML, and returns a hash representing that
|
29
|
+
# XML document. For example:
|
30
|
+
#
|
31
|
+
# FasterXmlSimple.xml_in("<root><something>1</something></root>")
|
32
|
+
# {"root"=>{"something"=>{"__content__"=>"1"}}}
|
33
|
+
#
|
34
|
+
# Faster XML Simple is designed to be a drop in replacement for the xml_in
|
35
|
+
# functionality of http://xml-simple.rubyforge.org
|
36
|
+
#
|
37
|
+
# The following options are supported:
|
38
|
+
#
|
39
|
+
# * <tt>contentkey</tt>: The key to use for the content of text elements,
|
40
|
+
# defaults to '\_\_content__'
|
41
|
+
# * <tt>forcearray</tt>: The list of elements which should always be returned
|
42
|
+
# as arrays. Under normal circumstances single element arrays are inlined.
|
43
|
+
# * <tt>suppressempty</tt>: The value to return for empty elements, pass +true+
|
44
|
+
# to remove empty elements entirely.
|
45
|
+
# * <tt>keeproot</tt>: By default the hash returned has a single key with the
|
46
|
+
# name of the root element. If the name of the root element isn't
|
47
|
+
# interesting to you, pass +false+.
|
48
|
+
# * <tt>forcecontent</tt>: By default a text element with no attributes, will
|
49
|
+
# be collapsed to just a string instead of a hash with a single key.
|
50
|
+
# Pass +true+ to prevent this.
|
51
|
+
#
|
52
|
+
#
|
53
|
+
def xml_in(string, options={})
|
54
|
+
new(string, options).out
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
def initialize(string, options) #:nodoc:
|
59
|
+
@doc = parse(string)
|
60
|
+
@options = default_options.merge options
|
61
|
+
end
|
62
|
+
|
63
|
+
def out #:nodoc:
|
64
|
+
if @options['keeproot']
|
65
|
+
{@doc.root.name => collapse(@doc.root)}
|
66
|
+
else
|
67
|
+
collapse(@doc.root)
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
private
|
72
|
+
def default_options
|
73
|
+
{'contentkey' => '__content__', 'forcearray' => [], 'keeproot'=>true}
|
74
|
+
end
|
75
|
+
|
76
|
+
def collapse(element)
|
77
|
+
result = hash_of_attributes(element)
|
78
|
+
if text_node? element
|
79
|
+
text = collapse_text(element)
|
80
|
+
result[content_key] = text if text =~ /\S/
|
81
|
+
elsif element.children?
|
82
|
+
element.inject(result) do |hash, child|
|
83
|
+
unless child.text?
|
84
|
+
child_result = collapse(child)
|
85
|
+
(hash[child.name] ||= []) << child_result
|
86
|
+
end
|
87
|
+
hash
|
88
|
+
end
|
89
|
+
end
|
90
|
+
if result.empty?
|
91
|
+
return empty_element
|
92
|
+
end
|
93
|
+
# Compact them to ensure it complies with the user's requests
|
94
|
+
inline_single_element_arrays(result)
|
95
|
+
remove_empty_elements(result) if suppress_empty?
|
96
|
+
if content_only?(result) && !force_content?
|
97
|
+
result[content_key]
|
98
|
+
else
|
99
|
+
result
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
def content_only?(result)
|
104
|
+
result.keys == [content_key]
|
105
|
+
end
|
106
|
+
|
107
|
+
def content_key
|
108
|
+
@options['contentkey']
|
109
|
+
end
|
110
|
+
|
111
|
+
def force_array?(key_name)
|
112
|
+
Array(@options['forcearray']).include?(key_name)
|
113
|
+
end
|
114
|
+
|
115
|
+
def inline_single_element_arrays(result)
|
116
|
+
result.each do |key, value|
|
117
|
+
if value.size == 1 && value.is_a?(Array) && !force_array?(key)
|
118
|
+
result[key] = value.first
|
119
|
+
end
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
123
|
+
def remove_empty_elements(result)
|
124
|
+
result.each do |key, value|
|
125
|
+
if value == empty_element
|
126
|
+
result.delete key
|
127
|
+
end
|
128
|
+
end
|
129
|
+
end
|
130
|
+
|
131
|
+
def suppress_empty?
|
132
|
+
@options['suppressempty'] == true
|
133
|
+
end
|
134
|
+
|
135
|
+
def empty_element
|
136
|
+
if !@options.has_key? 'suppressempty'
|
137
|
+
{}
|
138
|
+
else
|
139
|
+
@options['suppressempty']
|
140
|
+
end
|
141
|
+
end
|
142
|
+
|
143
|
+
# removes the content if it's nothing but blanks, prevents
|
144
|
+
# the hash being polluted with lots of content like "\n\t\t\t"
|
145
|
+
def suppress_empty_content(result)
|
146
|
+
result.delete content_key if result[content_key] !~ /\S/
|
147
|
+
end
|
148
|
+
|
149
|
+
def force_content?
|
150
|
+
@options['forcecontent']
|
151
|
+
end
|
152
|
+
|
153
|
+
# a text node is one with 1 or more child nodes which are
|
154
|
+
# text nodes, and no non-text children, there's no sensible
|
155
|
+
# way to support nodes which are text and markup like:
|
156
|
+
# <p>Something <b>Bold</b> </p>
|
157
|
+
def text_node?(element)
|
158
|
+
!element.text? && element.all? {|c| c.text?}
|
159
|
+
end
|
160
|
+
|
161
|
+
# takes a text node, and collapses it into a string
|
162
|
+
def collapse_text(element)
|
163
|
+
element.map {|c| c.content } * ''
|
164
|
+
end
|
165
|
+
|
166
|
+
def hash_of_attributes(element)
|
167
|
+
result = {}
|
168
|
+
element.each_attr do |attribute|
|
169
|
+
name = attribute.name
|
170
|
+
name = [attribute.ns, attribute.name].join(':') if attribute.ns?
|
171
|
+
result[name] = attribute.value
|
172
|
+
end
|
173
|
+
result
|
174
|
+
end
|
175
|
+
|
176
|
+
def parse(string)
|
177
|
+
if string == ''
|
178
|
+
string = ' '
|
179
|
+
end
|
180
|
+
XML::Parser.string(string).parse
|
181
|
+
end
|
182
|
+
end
|
183
|
+
|
184
|
+
class XmlSimple # :nodoc:
|
185
|
+
def self.xml_in(*args)
|
186
|
+
FasterXmlSimple.xml_in *args
|
187
|
+
end
|
188
|
+
end
|