xmlable 0.0.0.alpha1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/LICENSE.txt +21 -0
- data/README.md +245 -0
- data/lib/xmlable/attribute.rb +16 -0
- data/lib/xmlable/builder.rb +189 -0
- data/lib/xmlable/document.rb +16 -0
- data/lib/xmlable/element.rb +19 -0
- data/lib/xmlable/exports/base.rb +78 -0
- data/lib/xmlable/exports/json_exporter.rb +208 -0
- data/lib/xmlable/exports/xml_exporter.rb +179 -0
- data/lib/xmlable/exports.rb +11 -0
- data/lib/xmlable/handlers/attribute.rb +41 -0
- data/lib/xmlable/handlers/attribute_none.rb +10 -0
- data/lib/xmlable/handlers/base.rb +103 -0
- data/lib/xmlable/handlers/document.rb +33 -0
- data/lib/xmlable/handlers/element.rb +89 -0
- data/lib/xmlable/handlers/element_none.rb +10 -0
- data/lib/xmlable/handlers/elements.rb +15 -0
- data/lib/xmlable/handlers/mixins/described.rb +19 -0
- data/lib/xmlable/handlers/mixins/namespace.rb +40 -0
- data/lib/xmlable/handlers/mixins/tag.rb +24 -0
- data/lib/xmlable/handlers/namespace.rb +26 -0
- data/lib/xmlable/handlers/root.rb +9 -0
- data/lib/xmlable/handlers/root_none.rb +10 -0
- data/lib/xmlable/handlers/storage.rb +104 -0
- data/lib/xmlable/handlers.rb +23 -0
- data/lib/xmlable/mixins/attributes_storage.rb +195 -0
- data/lib/xmlable/mixins/bare_value.rb +41 -0
- data/lib/xmlable/mixins/castable.rb +93 -0
- data/lib/xmlable/mixins/container.rb +71 -0
- data/lib/xmlable/mixins/content_storage.rb +138 -0
- data/lib/xmlable/mixins/document_storage.rb +136 -0
- data/lib/xmlable/mixins/elements_storage.rb +219 -0
- data/lib/xmlable/mixins/export.rb +45 -0
- data/lib/xmlable/mixins/instantiable.rb +47 -0
- data/lib/xmlable/mixins/namespace_definitions_storage.rb +105 -0
- data/lib/xmlable/mixins/object.rb +95 -0
- data/lib/xmlable/mixins/options_storage.rb +39 -0
- data/lib/xmlable/mixins/root_storage.rb +162 -0
- data/lib/xmlable/mixins/standalone_attribute.rb +34 -0
- data/lib/xmlable/mixins/standalone_element.rb +47 -0
- data/lib/xmlable/mixins/value_storage.rb +84 -0
- data/lib/xmlable/mixins/wrapper.rb +37 -0
- data/lib/xmlable/mixins.rb +25 -0
- data/lib/xmlable/options/nokogiri_export.rb +19 -0
- data/lib/xmlable/options/storage.rb +97 -0
- data/lib/xmlable/options.rb +9 -0
- data/lib/xmlable/types.rb +31 -0
- data/lib/xmlable/version.rb +4 -0
- data/lib/xmlable.rb +49 -0
- metadata +149 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 8dac25c2580eed75d306634e799b8dc03d104da5
|
4
|
+
data.tar.gz: f764b71e734d47c4505e89c4b065ac5ba03b743a
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 27a75c87ddd0b08449cd2e0e1da18885aec9b3dbfe113b1cfc6236d1e8e3afd23676aafabcae610eeac48b2525811ab1723c10c3b35e763c446b71e6bee8a4f3
|
7
|
+
data.tar.gz: 0203c91ea3564b0ee5d590bbc5f6ad38785e3943046a30c88e0c131105ca2e94b942bbd0ae6eaa5d25ecd8e854aef074ffbe33942c04952d91522ef18208ceed
|
data/LICENSE.txt
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
The MIT License (MIT)
|
2
|
+
|
3
|
+
Copyright (c) 2016 Oleg Yashchuk
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
7
|
+
in the Software without restriction, including without limitation the rights
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
10
|
+
furnished to do so, subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in
|
13
|
+
all 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,
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
21
|
+
THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,245 @@
|
|
1
|
+
# XMLable
|
2
|
+
[![Build Status](https://travis-ci.org/zoer/lexer.svg)](https://travis-ci.org/zoer/lexer)
|
3
|
+
[![Code Climate](https://codeclimate.com/github/zoer/xmlable/badges/gpa.svg)](https://codeclimate.com/github/zoer/xmlable)
|
4
|
+
[![Version Eye](https://www.versioneye.com/ruby/xmlable/badge.png)](https://www.versioneye.com/ruby/xmlable)
|
5
|
+
[![Inline docs](http://inch-ci.org/github/zoer/xmlable.png)](http://inch-ci.org/github/zoer/xmlable)
|
6
|
+
[![Gem Version](https://badge.fury.io/rb/xmlable.svg)](http://badge.fury.io/rb/xmlable)
|
7
|
+
|
8
|
+
XMLable provides an ability to convert XML to Ruby object and back.
|
9
|
+
|
10
|
+
This probject is in active development and isn't ready for production yet.
|
11
|
+
|
12
|
+
## Installation
|
13
|
+
|
14
|
+
Add this line to your application's Gemfile:
|
15
|
+
|
16
|
+
```ruby
|
17
|
+
gem 'xmlable'
|
18
|
+
```
|
19
|
+
|
20
|
+
## Examples
|
21
|
+
|
22
|
+
### Basic usage
|
23
|
+
```ruby
|
24
|
+
# Describe XML structure
|
25
|
+
class Catalog
|
26
|
+
include XMLable::Document
|
27
|
+
|
28
|
+
root :catalog do
|
29
|
+
attribute :date, Date
|
30
|
+
element :size, Integer
|
31
|
+
elements :items, tag: 'item' do
|
32
|
+
attribute :position, Integer
|
33
|
+
element :title
|
34
|
+
element :desc, tag: 'description'
|
35
|
+
element :amount, Integer
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
xml = <<-XML
|
41
|
+
<?xml version="1.0"?>
|
42
|
+
<catalog date="2014-12-20">
|
43
|
+
<size>10</size>
|
44
|
+
<item position="1">
|
45
|
+
<title>Sumac Shoes</title>
|
46
|
+
<description>Capture the beauty</description>
|
47
|
+
<amount>3</amount>
|
48
|
+
</item>
|
49
|
+
<item position="2">
|
50
|
+
<title>Channing Oxford Shoes</title>
|
51
|
+
<description>Hand finished with a wash of color</description>
|
52
|
+
</item>
|
53
|
+
</catalog>
|
54
|
+
XML
|
55
|
+
|
56
|
+
doc = Catalog.from_xml(xml)
|
57
|
+
doc.catalog.date # => #<Date: 2014-12-20 ((2457012j,0s,0n),+0s,2299161j)>
|
58
|
+
doc.catalog.size # => 10
|
59
|
+
doc.catalog.items.size # => 2
|
60
|
+
doc.catalog.items[0].title # => "Sumac Shoes"
|
61
|
+
doc.catalog.items[0].desc # => "Capture the beauty"
|
62
|
+
doc.catalog.items[0].amount # => 3
|
63
|
+
doc.catalog.items[0].position # => 1
|
64
|
+
|
65
|
+
doc.to_json
|
66
|
+
#{
|
67
|
+
# "catalog": {
|
68
|
+
# "date": "2014-12-20",
|
69
|
+
# "size": 10,
|
70
|
+
# "items": [
|
71
|
+
# { "title": "Sumac Shoes", "desc": "Capture the beauty", "amount": 3, "position": 1 },
|
72
|
+
# { "title": "Channing Oxford Shoes", "desc": "Hand finished with a wash of color", "position": 2 }
|
73
|
+
# ]
|
74
|
+
# }
|
75
|
+
#}
|
76
|
+
|
77
|
+
json = {
|
78
|
+
catalog: {
|
79
|
+
date: "2014-12-20",
|
80
|
+
size: 10,
|
81
|
+
items: [
|
82
|
+
{ title: "Sumac Shoes", desc: "Capture the beauty", amount: 3, position: 1 },
|
83
|
+
{ title: "Channing Oxford Shoes", desc: "Hand finished with a wash of color", position: 2 }
|
84
|
+
]
|
85
|
+
}
|
86
|
+
}
|
87
|
+
|
88
|
+
# Initialize with JSON
|
89
|
+
doc = Catalog.new(json)
|
90
|
+
doc.catalog.date # => #<Date: 2014-12-20 ((2457012j,0s,0n),+0s,2299161j)>
|
91
|
+
doc.catalog.size # => 10
|
92
|
+
doc.catalog.items.size # => 2
|
93
|
+
doc.catalog.items[0].title # => "Sumac Shoes"
|
94
|
+
doc.catalog.items[0].desc # => "Capture the beauty"
|
95
|
+
doc.catalog.items[0].amount # => 3
|
96
|
+
doc.catalog.items[0].position # => 1
|
97
|
+
|
98
|
+
# By default all elements and attribute values are proxied. If you for some
|
99
|
+
# reason need to get real value just use the exclamation mark.
|
100
|
+
doc.catalog.date! # => #<Date: 2014-12-20 ((2457012j,0s,0n),+0s,2299161j)>
|
101
|
+
|
102
|
+
doc.to_xml
|
103
|
+
#<?xml version="1.0"?>
|
104
|
+
#<catalog date="2014-12-20">
|
105
|
+
# <size>10</size>
|
106
|
+
# <item position="1">
|
107
|
+
# <title>Sumac Shoes</title>
|
108
|
+
# <description>Capture the beauty</description>
|
109
|
+
# <amount>3</amount>
|
110
|
+
# </item>
|
111
|
+
# <item position="2">
|
112
|
+
# <title>Channing Oxford Shoes</title>
|
113
|
+
# <description>Hand finished with a wash of color</description>
|
114
|
+
# </item>
|
115
|
+
#</catalog>
|
116
|
+
```
|
117
|
+
|
118
|
+
### XML with namespaces
|
119
|
+
```ruby
|
120
|
+
xml = <<-XML
|
121
|
+
<?xml version="1.0"?>
|
122
|
+
<d:student xmlns="http://example.com" xmlns:d="http://foo.com/student" d:id="11">
|
123
|
+
<d:name d:position="2">Jeff Smith</d:name>
|
124
|
+
<info>
|
125
|
+
<city number="7">Beijing</city>
|
126
|
+
</info>
|
127
|
+
</d:student>
|
128
|
+
XML
|
129
|
+
|
130
|
+
class Student
|
131
|
+
include XMLable::Document
|
132
|
+
|
133
|
+
root :student, namespace: 'd' do
|
134
|
+
namespace nil, 'http://example.com'
|
135
|
+
# the last defined namespace will be set as default for the all following
|
136
|
+
# and nested elements and attributes. If you need to overwrite namespace
|
137
|
+
# just pass namespace: 'prefix' (see the root definition above).
|
138
|
+
namespace :d, 'http://foo.com/student'
|
139
|
+
|
140
|
+
attribute :id, :int
|
141
|
+
|
142
|
+
element :name do
|
143
|
+
attribute :position, :int
|
144
|
+
# You can describe content method of element which has also attributes
|
145
|
+
# besides the content. By default content if present will be exported into JSON with
|
146
|
+
# '__content' key. You can pase 'false' instead of name to ignore it.
|
147
|
+
content :fullname
|
148
|
+
end
|
149
|
+
|
150
|
+
# If namespace setting is passed it will be set as default for the all
|
151
|
+
# nested element and attributes.
|
152
|
+
element :info, namespace: nil do
|
153
|
+
element :city do
|
154
|
+
attribute :number, Integer
|
155
|
+
content :name
|
156
|
+
end
|
157
|
+
end
|
158
|
+
end
|
159
|
+
end
|
160
|
+
|
161
|
+
student = Student.from_xml(xml)
|
162
|
+
student.to_json
|
163
|
+
#{
|
164
|
+
# "student": {
|
165
|
+
# "id": 11,
|
166
|
+
# "name": {
|
167
|
+
# "fullname": "Jeff Smith",
|
168
|
+
# "position": 2
|
169
|
+
# },
|
170
|
+
# "info": {
|
171
|
+
# "city": {
|
172
|
+
# "name": "Beijing",
|
173
|
+
# "number": 7
|
174
|
+
# }
|
175
|
+
# }
|
176
|
+
# }
|
177
|
+
#}
|
178
|
+
|
179
|
+
# Back direction
|
180
|
+
other = Student.new(student.to_h)
|
181
|
+
|
182
|
+
other.to_xml
|
183
|
+
#<?xml version="1.0"?>
|
184
|
+
#<d:student xmlns="http://example.com" xmlns:d="http://foo.com/student" d:id="11">
|
185
|
+
# <d:name d:position="2">Jeff Smith</d:name>
|
186
|
+
# <info>
|
187
|
+
# <city number="7">Beijing</city>
|
188
|
+
# </info>
|
189
|
+
#</d:student>
|
190
|
+
```
|
191
|
+
|
192
|
+
### Undescribed document
|
193
|
+
It's also possible to load undescribed XML. In this case each XML element(not
|
194
|
+
attribute) will be represented as an array, so you have to use indexes to
|
195
|
+
access element values.
|
196
|
+
```ruby
|
197
|
+
xml = <<-XML
|
198
|
+
<?xml version="1.0"?>
|
199
|
+
<item id="11">
|
200
|
+
<name position="2">Bolt</name>
|
201
|
+
<info>
|
202
|
+
<color>Silver</color>
|
203
|
+
</info>
|
204
|
+
</item>
|
205
|
+
XML
|
206
|
+
|
207
|
+
class Item
|
208
|
+
include XMLable::Document
|
209
|
+
end
|
210
|
+
|
211
|
+
item = Item.from_xml(xml)
|
212
|
+
|
213
|
+
item.root.id # => "11"
|
214
|
+
item.root.name[0].position # => "2"
|
215
|
+
item.root.name[0] # => "Bolt"
|
216
|
+
item.root.info[0].color[0] # => "Silver"
|
217
|
+
|
218
|
+
item.to_h
|
219
|
+
#{
|
220
|
+
# "item": {
|
221
|
+
# "id": "11"
|
222
|
+
# "name": [{"position": 2", "__content": "Bolt"}]
|
223
|
+
# "info": [{ "color": ["Silver"]}]
|
224
|
+
# }
|
225
|
+
#}
|
226
|
+
|
227
|
+
item.to_xml
|
228
|
+
#<?xml version="1.0"?>
|
229
|
+
#<item id="11">
|
230
|
+
# <name position="2">Bolt</name>
|
231
|
+
# <info>
|
232
|
+
# <color>Silver</color>
|
233
|
+
# </info>
|
234
|
+
#</item>
|
235
|
+
```
|
236
|
+
|
237
|
+
## Contributing
|
238
|
+
|
239
|
+
Bug reports and pull requests are welcome on GitHub at https://github.com/zoer/xmlable.
|
240
|
+
|
241
|
+
|
242
|
+
## License
|
243
|
+
|
244
|
+
The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).
|
245
|
+
|
@@ -0,0 +1,16 @@
|
|
1
|
+
module XMLable
|
2
|
+
#
|
3
|
+
# Attribute module contains logic for standalone attribute object
|
4
|
+
#
|
5
|
+
module Attribute
|
6
|
+
def self.included(base)
|
7
|
+
base.include Mixins::Object
|
8
|
+
base.include Mixins::Castable
|
9
|
+
base.include Mixins::ValueStorage
|
10
|
+
base.include Mixins::StandaloneAttribute
|
11
|
+
base.include Mixins::OptionsStorage
|
12
|
+
base.include Mixins::BareValue
|
13
|
+
base.include Mixins::Instantiable
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,189 @@
|
|
1
|
+
module XMLable
|
2
|
+
#
|
3
|
+
# Builder class builds object that represents XML attribute and values
|
4
|
+
#
|
5
|
+
class Builder
|
6
|
+
include Singleton
|
7
|
+
|
8
|
+
class << self
|
9
|
+
#
|
10
|
+
# Build document object from XML document
|
11
|
+
#
|
12
|
+
# @param [Nokogiri::XML::Document] document
|
13
|
+
# @param [XMLable::Handlers::Document] handler
|
14
|
+
#
|
15
|
+
# @return [XMLable::Mixins::Object]
|
16
|
+
#
|
17
|
+
def build_document(document, handler)
|
18
|
+
obj = handler.proxy.new({}, document, handler)
|
19
|
+
populate_document(obj, document)
|
20
|
+
end
|
21
|
+
|
22
|
+
#
|
23
|
+
# Build attribute object from XML attribute
|
24
|
+
#
|
25
|
+
# @param [Nogogiri::XML::Attribute] attribute
|
26
|
+
# @param [XMLable::Handlers::Base] handler
|
27
|
+
#
|
28
|
+
# @return [XMLable::Mixins::Object]
|
29
|
+
#
|
30
|
+
def build_attribute(attribute, handler)
|
31
|
+
obj = handler.proxy.new({}, attribute, handler)
|
32
|
+
populate_attribute(obj, attribute)
|
33
|
+
end
|
34
|
+
|
35
|
+
#
|
36
|
+
# Build element object from XML element
|
37
|
+
#
|
38
|
+
# @param [Nogogiri::XML::Element] node
|
39
|
+
# @param [XMLable::Handlers::Base] handler
|
40
|
+
#
|
41
|
+
# @return [XMLable::Mixins::Object]
|
42
|
+
#
|
43
|
+
def build_element(node, handler)
|
44
|
+
obj = handler.proxy.new({}, node, handler)
|
45
|
+
populate_element(obj, node)
|
46
|
+
end
|
47
|
+
|
48
|
+
#
|
49
|
+
# Populate document object
|
50
|
+
#
|
51
|
+
# @param [XMLable::Mixins::Object] obj
|
52
|
+
# @param [Nogogiri::XML::Document] node
|
53
|
+
#
|
54
|
+
# @return [XMLable::Mixins::Object]
|
55
|
+
#
|
56
|
+
def populate_document(obj, node)
|
57
|
+
obj.__set_root(node.root)
|
58
|
+
obj
|
59
|
+
end
|
60
|
+
|
61
|
+
#
|
62
|
+
# Populate element object
|
63
|
+
#
|
64
|
+
# @param [XMLable::Mixins::Object] obj
|
65
|
+
# @param [Nogogiri::XML::Element] node
|
66
|
+
#
|
67
|
+
# @return [XMLable::Mixins::Object]
|
68
|
+
#
|
69
|
+
def populate_element(obj, node)
|
70
|
+
node.namespace_definitions.each { |ns| obj.__set_namespace_definition(ns) }
|
71
|
+
node.elements.each { |el| obj.__set_element(el) }
|
72
|
+
node.attributes.each { |_, att| obj.__set_attribute(att) }
|
73
|
+
obj.__set_content(node)
|
74
|
+
obj
|
75
|
+
end
|
76
|
+
|
77
|
+
#
|
78
|
+
# Populate attribute object
|
79
|
+
#
|
80
|
+
# @param [XMLable::Mixins::Object] obj
|
81
|
+
# @param [Nogogiri::XML::Attr] node
|
82
|
+
#
|
83
|
+
# @return [XMLable::Mixins::Object]
|
84
|
+
#
|
85
|
+
def populate_attribute(obj, node)
|
86
|
+
obj.tap { |o| o.__set_value(node) }
|
87
|
+
end
|
88
|
+
|
89
|
+
#
|
90
|
+
# Find defined type
|
91
|
+
#
|
92
|
+
# @param [Object] type
|
93
|
+
#
|
94
|
+
# @return [Class] returns found type or define new one if it's not found
|
95
|
+
#
|
96
|
+
def find_type(type)
|
97
|
+
type = type.to_s if type.is_a?(Symbol)
|
98
|
+
klass = instance.defined_types[type]
|
99
|
+
klass ? klass : define_type(type)
|
100
|
+
end
|
101
|
+
|
102
|
+
#
|
103
|
+
# Wrap type with additional logic
|
104
|
+
#
|
105
|
+
# @param [Class] klass
|
106
|
+
#
|
107
|
+
# @return [Class] returns wrapped class
|
108
|
+
#
|
109
|
+
def wrap_type(klass, &block)
|
110
|
+
Class.new do
|
111
|
+
include Mixins::Object
|
112
|
+
include Mixins::Wrapper
|
113
|
+
include Mixins::Castable
|
114
|
+
include Mixins::OptionsStorage
|
115
|
+
class_eval(&block) if block_given?
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
119
|
+
#
|
120
|
+
# Inherit type and set additional settings
|
121
|
+
#
|
122
|
+
# @param [Class] klass
|
123
|
+
#
|
124
|
+
# @return [Class] returns wrapped class
|
125
|
+
#
|
126
|
+
def inherit_type(klass, &block)
|
127
|
+
Class.new(klass) do
|
128
|
+
class_eval(&block) if block_given?
|
129
|
+
end
|
130
|
+
end
|
131
|
+
|
132
|
+
#
|
133
|
+
# Define new type
|
134
|
+
#
|
135
|
+
# @param [Array<Object>] names type's names(aliases)
|
136
|
+
#
|
137
|
+
# @return [Class]
|
138
|
+
#
|
139
|
+
def define_type(*names, &block)
|
140
|
+
names = names.map { |n| n.is_a?(Symbol) ? n.to_s : n }
|
141
|
+
main = names.first
|
142
|
+
klass = wrapped_type?(main) ? wrap_type(main, &block) : inherit_type(main, &block)
|
143
|
+
names.each { |n| instance.defined_types[n] = klass }
|
144
|
+
klass
|
145
|
+
end
|
146
|
+
|
147
|
+
#
|
148
|
+
# Is the given class wrapped?
|
149
|
+
#
|
150
|
+
# @return [Boolean]
|
151
|
+
#
|
152
|
+
def wrapped_type?(klass)
|
153
|
+
return true if !klass.is_a?(Class)
|
154
|
+
return false if klass.ancestors.include?(Mixins::StandaloneElement)
|
155
|
+
return false if klass.ancestors.include?(Mixins::StandaloneAttribute)
|
156
|
+
true
|
157
|
+
end
|
158
|
+
|
159
|
+
#
|
160
|
+
# Get proxy for the given type
|
161
|
+
#
|
162
|
+
# @param [Object] type type's name
|
163
|
+
#
|
164
|
+
# @return [Class] returns type's proxy class
|
165
|
+
#
|
166
|
+
def proxy_for(type)
|
167
|
+
find_type(type).dup
|
168
|
+
end
|
169
|
+
|
170
|
+
#
|
171
|
+
# Get container proxy for the given class
|
172
|
+
#
|
173
|
+
# @param [Class] klass
|
174
|
+
#
|
175
|
+
# @return [Class]
|
176
|
+
#
|
177
|
+
def container_proxy_for(klass)
|
178
|
+
Class.new(klass) { include Mixins::Container }
|
179
|
+
end
|
180
|
+
end
|
181
|
+
|
182
|
+
# @return [Hash]
|
183
|
+
attr_reader :defined_types
|
184
|
+
|
185
|
+
def initialize
|
186
|
+
@defined_types = {}
|
187
|
+
end
|
188
|
+
end
|
189
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
module XMLable
|
2
|
+
#
|
3
|
+
# Document module contains logic for XML document object
|
4
|
+
#
|
5
|
+
module Document
|
6
|
+
def self.included(base)
|
7
|
+
base.include Mixins::Object
|
8
|
+
base.include Mixins::Export
|
9
|
+
base.include Mixins::OptionsStorage
|
10
|
+
base.include Mixins::Instantiable
|
11
|
+
base.include Mixins::Castable
|
12
|
+
base.include Mixins::DocumentStorage
|
13
|
+
base.include Mixins::RootStorage
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
module XMLable
|
2
|
+
#
|
3
|
+
# Element module contains logic for standalone element object
|
4
|
+
#
|
5
|
+
module Element
|
6
|
+
def self.included(base)
|
7
|
+
base.include Mixins::Object
|
8
|
+
base.include Mixins::Castable
|
9
|
+
base.include Mixins::ElementsStorage
|
10
|
+
base.include Mixins::AttributesStorage
|
11
|
+
base.include Mixins::ContentStorage
|
12
|
+
base.include Mixins::StandaloneElement
|
13
|
+
base.include Mixins::OptionsStorage
|
14
|
+
base.include Mixins::NamespaceDefinitionsStorage
|
15
|
+
base.include Mixins::BareValue
|
16
|
+
base.include Mixins::Instantiable
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,78 @@
|
|
1
|
+
module XMLable
|
2
|
+
module Exports
|
3
|
+
#
|
4
|
+
# Base class contains the base export logic
|
5
|
+
#
|
6
|
+
class Base
|
7
|
+
#
|
8
|
+
# Initialize
|
9
|
+
#
|
10
|
+
# @param [XMLable::Mixins::Object] element
|
11
|
+
# @param [Hash] opts
|
12
|
+
#
|
13
|
+
def initialize(element, opts = {})
|
14
|
+
@element = element
|
15
|
+
@opts = opts
|
16
|
+
end
|
17
|
+
|
18
|
+
#
|
19
|
+
# Is this object empty?
|
20
|
+
#
|
21
|
+
# @param [Nokogiri::XML::Node] node
|
22
|
+
#
|
23
|
+
# @return [Boolean]
|
24
|
+
#
|
25
|
+
def empty?(node)
|
26
|
+
node.instance_variable_get(:@__element).__empty?
|
27
|
+
end
|
28
|
+
|
29
|
+
#
|
30
|
+
# Is the object described by user?
|
31
|
+
#
|
32
|
+
# @param [Nokogiri::XML::Node] node
|
33
|
+
#
|
34
|
+
# @return [Boolean]
|
35
|
+
#
|
36
|
+
def described?(node)
|
37
|
+
node.instance_variable_get(:@__handler).described?
|
38
|
+
end
|
39
|
+
|
40
|
+
#
|
41
|
+
# Get node's nested options
|
42
|
+
#
|
43
|
+
# @param [Nokogiri::XML::Node] node
|
44
|
+
#
|
45
|
+
# @return [XMLable::Options::Storage]
|
46
|
+
#
|
47
|
+
def node_nested_options(node)
|
48
|
+
return Options::Storage.new unless node
|
49
|
+
parent = node.respond_to?(:parent) ? node.parent : nil
|
50
|
+
node_nested_options(parent).merge_opts(node_options(node))
|
51
|
+
end
|
52
|
+
|
53
|
+
#
|
54
|
+
# Get node's options
|
55
|
+
#
|
56
|
+
# @param [Nokogiri::XML::Node] node
|
57
|
+
#
|
58
|
+
# @return [XMLable::Options::Storage]
|
59
|
+
#
|
60
|
+
def node_options(node)
|
61
|
+
h = node.instance_variable_get(:@__handler)
|
62
|
+
h && h.options? ? h.options : Options::Storage.new
|
63
|
+
end
|
64
|
+
|
65
|
+
#
|
66
|
+
# Merge node's options
|
67
|
+
#
|
68
|
+
# @param [Nokogiri::XML::Node] node
|
69
|
+
# @param [XMLable::Options::Storage] opts
|
70
|
+
#
|
71
|
+
# @return [XMLable::Options::Storage]
|
72
|
+
#
|
73
|
+
def node_merged_opts(node, opts = Options::Storage.new)
|
74
|
+
opts.merge_opts(node_options(node))
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|