xmlable 0.0.0.alpha1
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/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
@@ -0,0 +1,19 @@
|
|
1
|
+
module XMLable
|
2
|
+
module Handlers
|
3
|
+
module Mixins
|
4
|
+
#
|
5
|
+
# Described module contains described and null object handlers logic
|
6
|
+
#
|
7
|
+
module Described
|
8
|
+
#
|
9
|
+
# Is this handlers described by user or not?
|
10
|
+
#
|
11
|
+
# @return [Boolean]
|
12
|
+
#
|
13
|
+
def described?
|
14
|
+
!self.class.name.end_with?('None')
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
module XMLable
|
2
|
+
module Handlers
|
3
|
+
module Mixins
|
4
|
+
#
|
5
|
+
# Namespace contains
|
6
|
+
#
|
7
|
+
module Namespace
|
8
|
+
#
|
9
|
+
# @see XMLable::Handlers::Base#initialize
|
10
|
+
#
|
11
|
+
def initialize(*args, &block)
|
12
|
+
if args.last.is_a?(Hash)
|
13
|
+
@namespace = args.last.delete(:namespace)
|
14
|
+
@namespace = @namespace.to_s if @namespace
|
15
|
+
end
|
16
|
+
super
|
17
|
+
end
|
18
|
+
|
19
|
+
#
|
20
|
+
# Get handler object namespace
|
21
|
+
#
|
22
|
+
# @return [String, nil]
|
23
|
+
#
|
24
|
+
def namespace_prefix
|
25
|
+
@namespace if @namespace
|
26
|
+
end
|
27
|
+
|
28
|
+
#
|
29
|
+
# Get handler combined key.
|
30
|
+
# It adds namespace to key if it exists.
|
31
|
+
#
|
32
|
+
# @return [String, nil]
|
33
|
+
#
|
34
|
+
def key
|
35
|
+
[@namespace, @tag].compact.map(&:to_s).join(":")
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
module XMLable
|
2
|
+
module Handlers
|
3
|
+
module Mixins
|
4
|
+
#
|
5
|
+
# Tag module contains tagable handlers
|
6
|
+
#
|
7
|
+
module Tag
|
8
|
+
# @return [String] returns XML object tag name
|
9
|
+
attr_reader :tag
|
10
|
+
|
11
|
+
#
|
12
|
+
# @see XMLable::Handler::Base#intialize
|
13
|
+
#
|
14
|
+
def initialize(*args, &block)
|
15
|
+
super
|
16
|
+
if args.last.is_a?(Hash)
|
17
|
+
@tag = args.last.delete(:tag)
|
18
|
+
@tag = @tag ? @tag.to_s : @name
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
module XMLable
|
2
|
+
module Handlers
|
3
|
+
#
|
4
|
+
# Namespace handles XML namespace objects
|
5
|
+
#
|
6
|
+
class Namespace
|
7
|
+
# @return [Symbol, nil] returns namespace's prefix
|
8
|
+
attr_reader :prefix
|
9
|
+
# @return [Symbol] returns namespace's URI
|
10
|
+
attr_reader :prefix, :href
|
11
|
+
|
12
|
+
#
|
13
|
+
# @param [Symbol, String, nil] prefix_or_href namespace's URI or prefix
|
14
|
+
# @param [String] href namespace's URI
|
15
|
+
#
|
16
|
+
def initialize(prefix_or_href = nil, href = nil, _opts = {})
|
17
|
+
if prefix.to_s =~ URI.regexp
|
18
|
+
@href = prefix_or_href
|
19
|
+
else
|
20
|
+
@prefix = prefix_or_href
|
21
|
+
@href = href
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,104 @@
|
|
1
|
+
module XMLable
|
2
|
+
module Handlers
|
3
|
+
#
|
4
|
+
# Storage stores handlers
|
5
|
+
#
|
6
|
+
class Storage
|
7
|
+
# @return [Array<XMLable::Handlers::Base>]
|
8
|
+
attr_reader :storage
|
9
|
+
|
10
|
+
#
|
11
|
+
# @param [Hash] opts additional options
|
12
|
+
# @option opts [XMLable::Handlers::Base] :default default handler's class
|
13
|
+
# @param [Array] storage initial handlers to store
|
14
|
+
#
|
15
|
+
def initialize(opts = {}, storage = [])
|
16
|
+
@opts = opts
|
17
|
+
@storage = storage
|
18
|
+
end
|
19
|
+
|
20
|
+
#
|
21
|
+
# Find or create handler for the XML node
|
22
|
+
#
|
23
|
+
# @param [XML::Nokogiri::Node] node
|
24
|
+
#
|
25
|
+
# @return [XMLable::Handlers::Base]
|
26
|
+
#
|
27
|
+
def for_xml_object(node)
|
28
|
+
tag = node.name.to_s
|
29
|
+
namespace = node.namespace.prefix if node.namespace
|
30
|
+
namespace = namespace.to_s if namespace
|
31
|
+
handler_with_tag!(tag, namespace: namespace)
|
32
|
+
end
|
33
|
+
|
34
|
+
#
|
35
|
+
# Append new handler to storage
|
36
|
+
#
|
37
|
+
# @note Described handler is always on top of the list
|
38
|
+
#
|
39
|
+
# @param [XMLable::Handler::Base] handler
|
40
|
+
#
|
41
|
+
def <<(handler)
|
42
|
+
@storage << handler
|
43
|
+
@storage = @storage.sort_by { |h| !h.described?.to_s }
|
44
|
+
end
|
45
|
+
|
46
|
+
#
|
47
|
+
# Find handler with given tag
|
48
|
+
#
|
49
|
+
# @param [String] tag element tag name
|
50
|
+
# @param [Hash] opts
|
51
|
+
# @option opts [String, nil] :namespace element namespace
|
52
|
+
#
|
53
|
+
# @return [XMLable::Handlers::Base, nil] returns handler if it's found,
|
54
|
+
# otherwise return +nil+
|
55
|
+
#
|
56
|
+
def handler_with_tag(tag, opts = {})
|
57
|
+
match = @storage.find { |h| h.tag == tag }
|
58
|
+
return match if !match || !opts.key?(:namespace)
|
59
|
+
return match if opts[:namespace] == false
|
60
|
+
match.namespace_prefix == opts[:namespace] ? match : nil
|
61
|
+
end
|
62
|
+
|
63
|
+
#
|
64
|
+
# Find handler with given tag or create a new one
|
65
|
+
#
|
66
|
+
# @param [String] tag element tag name
|
67
|
+
# @param [Hash] opts
|
68
|
+
# @option opts [String, nil] :namespace element namespace
|
69
|
+
#
|
70
|
+
# @return [XMLable::Handlers::Base]
|
71
|
+
#
|
72
|
+
def handler_with_tag!(tag, opts = {})
|
73
|
+
match = handler_with_tag(tag, opts)
|
74
|
+
return match if match
|
75
|
+
default_handler.build(tag, opts).tap { |h| self << h }
|
76
|
+
end
|
77
|
+
|
78
|
+
#
|
79
|
+
# Clone handlers storage
|
80
|
+
#
|
81
|
+
# @return [XMLable::Handers::Storage]
|
82
|
+
#
|
83
|
+
def clone
|
84
|
+
self.class.new(@opts, storage.clone)
|
85
|
+
end
|
86
|
+
|
87
|
+
#
|
88
|
+
# Default handler class
|
89
|
+
#
|
90
|
+
# @return [XMLable::Handlers::Base] returns null object handler
|
91
|
+
#
|
92
|
+
def default_handler
|
93
|
+
@opts[:default]
|
94
|
+
end
|
95
|
+
|
96
|
+
#
|
97
|
+
# @return [String]
|
98
|
+
#
|
99
|
+
def inspect
|
100
|
+
"#<XMLable::Handlers::Storage #{@storage.map(&:key).join(', ')} >"
|
101
|
+
end
|
102
|
+
end
|
103
|
+
end
|
104
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
module XMLable
|
2
|
+
#
|
3
|
+
# Handlers module contains the handlers objects
|
4
|
+
#
|
5
|
+
module Handlers
|
6
|
+
end
|
7
|
+
end
|
8
|
+
|
9
|
+
require_relative 'handlers/mixins/namespace'
|
10
|
+
require_relative 'handlers/mixins/described'
|
11
|
+
require_relative 'handlers/mixins/tag'
|
12
|
+
|
13
|
+
require_relative 'handlers/base'
|
14
|
+
require_relative 'handlers/attribute'
|
15
|
+
require_relative 'handlers/attribute_none'
|
16
|
+
require_relative 'handlers/element'
|
17
|
+
require_relative 'handlers/elements'
|
18
|
+
require_relative 'handlers/element_none'
|
19
|
+
require_relative 'handlers/root'
|
20
|
+
require_relative 'handlers/root_none'
|
21
|
+
require_relative 'handlers/document'
|
22
|
+
require_relative 'handlers/namespace'
|
23
|
+
require_relative 'handlers/storage'
|
@@ -0,0 +1,195 @@
|
|
1
|
+
module XMLable
|
2
|
+
module Mixins
|
3
|
+
#
|
4
|
+
# AttributesStorage module contains the logic for object that able to
|
5
|
+
# store XML attributes
|
6
|
+
#
|
7
|
+
module AttributesStorage
|
8
|
+
def self.included(base)
|
9
|
+
base.extend(ClassMethods)
|
10
|
+
end
|
11
|
+
|
12
|
+
#
|
13
|
+
# Set XML attribute
|
14
|
+
#
|
15
|
+
# @param [Nokogiri::XML::Attr, nil] att
|
16
|
+
# @param [Hash] opts
|
17
|
+
# @option opts [String] :tag attribute's name
|
18
|
+
# @option opts [String] :namespace attribute's namespace
|
19
|
+
#
|
20
|
+
# @api private
|
21
|
+
#
|
22
|
+
def __set_attribute(att, opts = {})
|
23
|
+
unless att
|
24
|
+
@__node[opts[:tag]] = att
|
25
|
+
att = @__node.attributes[opts[:tag]]
|
26
|
+
if opts[:namespace]
|
27
|
+
att.namespace = att.namespace_scopes.find { |n| n.prefix == opts[:namespace] }
|
28
|
+
end
|
29
|
+
end
|
30
|
+
h = __attributes_handlers.for_xml_object(att)
|
31
|
+
att.instance_variable_set(:@__handler, h)
|
32
|
+
__attributes[h.key] = h.from_xml_attribute(att)
|
33
|
+
end
|
34
|
+
|
35
|
+
#
|
36
|
+
# Attributes which current object holds
|
37
|
+
#
|
38
|
+
# @api private
|
39
|
+
#
|
40
|
+
# @return [Hash(String => Array<XMLable::Mixins::Object>)]
|
41
|
+
#
|
42
|
+
def __attributes
|
43
|
+
@__attributes ||= {}
|
44
|
+
end
|
45
|
+
|
46
|
+
#
|
47
|
+
# Is this object empty?
|
48
|
+
#
|
49
|
+
# @api private
|
50
|
+
#
|
51
|
+
# @return [Hash(String => Array<XMLable::Mixins::Object>)]
|
52
|
+
#
|
53
|
+
def __empty?
|
54
|
+
return false unless super
|
55
|
+
__attributes.values.all?(&:__empty?)
|
56
|
+
end
|
57
|
+
|
58
|
+
def method_missing(name, *args, &block)
|
59
|
+
h = __has_attribute_handler?(name)
|
60
|
+
return super unless h
|
61
|
+
|
62
|
+
if name.to_s.end_with?('=')
|
63
|
+
__attribute_object_set(h, args.first)
|
64
|
+
else
|
65
|
+
__attribute_object_get(h)
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
#
|
70
|
+
# Does this object contain attribute with given key?
|
71
|
+
#
|
72
|
+
# @return [XMLable::Mixins::Object, false]
|
73
|
+
#
|
74
|
+
def key?(key)
|
75
|
+
super || __has_attribute_handler?(key)
|
76
|
+
end
|
77
|
+
|
78
|
+
#
|
79
|
+
# Get attribute object by its key
|
80
|
+
#
|
81
|
+
# @param [String] key attribute key
|
82
|
+
#
|
83
|
+
# @return [XMLable::Mixins::Object, nil]
|
84
|
+
#
|
85
|
+
def [](key)
|
86
|
+
h = __has_attribute_handler?(key)
|
87
|
+
h ? __attribute_object_get(h) : super
|
88
|
+
end
|
89
|
+
|
90
|
+
#
|
91
|
+
# Set attribute value
|
92
|
+
#
|
93
|
+
# @param [String] key attribute key
|
94
|
+
# @param [Object] val new value
|
95
|
+
#
|
96
|
+
# @return [XMLable::Mixins::Object, nil]
|
97
|
+
#
|
98
|
+
def []=(key, val)
|
99
|
+
h = __has_attribute_handler?(key)
|
100
|
+
h ? __attribute_object_set(h, val) : super
|
101
|
+
end
|
102
|
+
|
103
|
+
#
|
104
|
+
# Find attribute handler by its key
|
105
|
+
#
|
106
|
+
# @param [Symbol, String] key
|
107
|
+
#
|
108
|
+
# @api private
|
109
|
+
#
|
110
|
+
# @return [XMLable::Handlers::Attribute, XMLable::Handlers::AttributeNone, nil]
|
111
|
+
#
|
112
|
+
def __has_attribute_handler?(key)
|
113
|
+
key = key.to_s.gsub(/[=!]$/, '')
|
114
|
+
__attributes_handlers.storage.find { |h| h.method_name == key }
|
115
|
+
end
|
116
|
+
|
117
|
+
#
|
118
|
+
# Get attribute object
|
119
|
+
#
|
120
|
+
# @param [XMLable::Handlers::Attribute, XMLable::Handlers::AttributeNone] h
|
121
|
+
#
|
122
|
+
# @api private
|
123
|
+
#
|
124
|
+
# @return [XMLable::Mixins::Object]
|
125
|
+
#
|
126
|
+
def __attribute_object_get(h)
|
127
|
+
unless __attributes.key?(h.key)
|
128
|
+
__set_attribute(nil, tag: h.tag, namespace: h.namespace_prefix)
|
129
|
+
end
|
130
|
+
__attributes[h.key]
|
131
|
+
end
|
132
|
+
|
133
|
+
#
|
134
|
+
# Set attribute object value
|
135
|
+
#
|
136
|
+
# @param [XMLable::Handlers::Attribute, XMLable::Handlers::AttributeNone, nil] h
|
137
|
+
# @param [Object] val new value
|
138
|
+
#
|
139
|
+
# @api private
|
140
|
+
#
|
141
|
+
def __attribute_object_set(h, val)
|
142
|
+
__attribute_object_get(h).__overwrite_value(val)
|
143
|
+
end
|
144
|
+
|
145
|
+
#
|
146
|
+
# Initialize attribute object with value
|
147
|
+
#
|
148
|
+
# @param [XMLable::Handlers::Attribute, XMLable::Handlers::AttributeNone, nil] h
|
149
|
+
# @param [Object] val
|
150
|
+
#
|
151
|
+
# @api private
|
152
|
+
#
|
153
|
+
def __attribute_object_initialize(h, value)
|
154
|
+
__attribute_object_get(h).__overwrite_value(value)
|
155
|
+
end
|
156
|
+
|
157
|
+
#
|
158
|
+
# Attributes handlers storage
|
159
|
+
#
|
160
|
+
# @return [XMLable::Handlers::Storage]
|
161
|
+
#
|
162
|
+
def __attributes_handlers
|
163
|
+
@__attributes_handler ||= self.class.__attributes_handlers.clone
|
164
|
+
end
|
165
|
+
|
166
|
+
module ClassMethods
|
167
|
+
#
|
168
|
+
# Attributes handlers storage
|
169
|
+
#
|
170
|
+
# @return [XMLable::Handlers::Storage]
|
171
|
+
#
|
172
|
+
def __attributes_handlers
|
173
|
+
@__attributes_handlers ||=
|
174
|
+
__nested(:@__attributes_handlers) || Handlers::Storage.new(default: Handlers::AttributeNone)
|
175
|
+
end
|
176
|
+
|
177
|
+
#
|
178
|
+
# Describe object attribute
|
179
|
+
#
|
180
|
+
# @see XMLable::Handler::Base#build
|
181
|
+
#
|
182
|
+
# @return [XMLable::Handlers::Storage]
|
183
|
+
#
|
184
|
+
def attribute(*args, &block)
|
185
|
+
opts = args.last.is_a?(Hash) ? args.pop : {}
|
186
|
+
if __default_namespace && !opts.key?(:namespace)
|
187
|
+
opts[:namespace] = __default_namespace
|
188
|
+
end
|
189
|
+
h = Handlers::Attribute.build(*args, opts, &block)
|
190
|
+
__attributes_handlers << h
|
191
|
+
end
|
192
|
+
end
|
193
|
+
end
|
194
|
+
end
|
195
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
module XMLable
|
2
|
+
module Mixins
|
3
|
+
#
|
4
|
+
# BareValue contains logic to get the bare value.
|
5
|
+
# All XML object such as Integer, Date, String, etc are wrapped with the
|
6
|
+
# proxy classes. This module helps to unwrap the real value.
|
7
|
+
#
|
8
|
+
module BareValue
|
9
|
+
def method_missing(name, *args, &block)
|
10
|
+
return super unless name.to_s =~ /!$/
|
11
|
+
return super unless key?(name)
|
12
|
+
name = name.to_s.gsub(/!$/,'').to_sym
|
13
|
+
__extract_bare_value(super)
|
14
|
+
end
|
15
|
+
|
16
|
+
#
|
17
|
+
# Get object value
|
18
|
+
# It unwraps the object value if object key ends with '!' symbol.
|
19
|
+
#
|
20
|
+
# @return [XMLable::Mixins::Object, Object, nil]
|
21
|
+
#
|
22
|
+
def [](key)
|
23
|
+
return super unless key.to_s =~ /!$/
|
24
|
+
__extract_bare_value(super)
|
25
|
+
end
|
26
|
+
|
27
|
+
#
|
28
|
+
# Unwrap objects
|
29
|
+
#
|
30
|
+
# @param [XMLable::Mixins::Object, Array<XMLable::Mixins::Object>] obj
|
31
|
+
#
|
32
|
+
# @api private
|
33
|
+
#
|
34
|
+
# @return [Object, Array<Object>]
|
35
|
+
#
|
36
|
+
def __extract_bare_value(obj)
|
37
|
+
obj.respond_to?(:map) ? obj.map(&:__object) : obj.__object
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,93 @@
|
|
1
|
+
module XMLable
|
2
|
+
module Mixins
|
3
|
+
#
|
4
|
+
# Castable module contains the logic that helps to cast values from
|
5
|
+
# different forms to XML/JSON and back.
|
6
|
+
#
|
7
|
+
module Castable
|
8
|
+
def self.included(base)
|
9
|
+
base.extend(ClassMethods)
|
10
|
+
end
|
11
|
+
|
12
|
+
#
|
13
|
+
# Cast object from XML value
|
14
|
+
#
|
15
|
+
# @param [String] val
|
16
|
+
#
|
17
|
+
# @api private
|
18
|
+
#
|
19
|
+
# @return [Object]
|
20
|
+
#
|
21
|
+
def __cast(val)
|
22
|
+
val
|
23
|
+
end
|
24
|
+
|
25
|
+
#
|
26
|
+
# Export value to XML/JSON
|
27
|
+
#
|
28
|
+
# @param [Object] val
|
29
|
+
#
|
30
|
+
# @api private
|
31
|
+
#
|
32
|
+
# @return [Object]
|
33
|
+
#
|
34
|
+
def __export(val)
|
35
|
+
val.to_s
|
36
|
+
end
|
37
|
+
|
38
|
+
#
|
39
|
+
# Export value to XML
|
40
|
+
#
|
41
|
+
# @param [Object] val
|
42
|
+
#
|
43
|
+
# @api private
|
44
|
+
#
|
45
|
+
# @return [String]
|
46
|
+
#
|
47
|
+
def __export_to_xml(val)
|
48
|
+
__export(val).to_s
|
49
|
+
end
|
50
|
+
|
51
|
+
#
|
52
|
+
# Export value to JSON
|
53
|
+
#
|
54
|
+
# @param [Object] val
|
55
|
+
#
|
56
|
+
# @api private
|
57
|
+
#
|
58
|
+
# @return [Object]
|
59
|
+
#
|
60
|
+
def __export_to_json(val)
|
61
|
+
__export(val).to_s
|
62
|
+
end
|
63
|
+
|
64
|
+
#
|
65
|
+
# Is this object empty?
|
66
|
+
#
|
67
|
+
# @api private
|
68
|
+
#
|
69
|
+
# @return [Boolean]
|
70
|
+
#
|
71
|
+
def __empty(val)
|
72
|
+
val.respond_to?(:empty?) && val.empty? ||
|
73
|
+
val.is_a?(String) && val == '' ||
|
74
|
+
val.nil?
|
75
|
+
end
|
76
|
+
|
77
|
+
module ClassMethods
|
78
|
+
# @return [Array<Symbol>] retuns list of the setup methods
|
79
|
+
CAST_METHODS = %i[cast export export_to_json export_to_xml empty]
|
80
|
+
|
81
|
+
#
|
82
|
+
# Override method missing to get the setup methods be available
|
83
|
+
#
|
84
|
+
# @see XMLable::Mixins::Castable::ClassMethods::CAST_METHODS
|
85
|
+
#
|
86
|
+
def method_missing(name, *args, &block)
|
87
|
+
return super unless CAST_METHODS.include?(name)
|
88
|
+
define_method("__#{name}", &block) if block_given?
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|
@@ -0,0 +1,71 @@
|
|
1
|
+
module XMLable
|
2
|
+
module Mixins
|
3
|
+
#
|
4
|
+
# Container module contains the logic for the XML objects groups
|
5
|
+
#
|
6
|
+
module Container
|
7
|
+
# @return [XMLable::Handlers::Elements]
|
8
|
+
attr_reader :__handler
|
9
|
+
|
10
|
+
#
|
11
|
+
# Create new element
|
12
|
+
#
|
13
|
+
# @param [Object] args element initial params
|
14
|
+
#
|
15
|
+
# @return [XMLable::Mixins::Object] returns created element
|
16
|
+
#
|
17
|
+
def new(args = nil)
|
18
|
+
xml = Nokogiri::XML::Element.new(@__handler.tag.to_s, @__parent_node)
|
19
|
+
el = @__handler.from_xml_element(xml)
|
20
|
+
el.__initialize_with(args) if args
|
21
|
+
@__parent_node << xml
|
22
|
+
self << el
|
23
|
+
el
|
24
|
+
end
|
25
|
+
|
26
|
+
#
|
27
|
+
# Set current object handler
|
28
|
+
#
|
29
|
+
# @param [XMLable::Handlers::Elements] handler
|
30
|
+
#
|
31
|
+
# @api private
|
32
|
+
#
|
33
|
+
def __set_handler(handler)
|
34
|
+
@__handler = handler
|
35
|
+
end
|
36
|
+
|
37
|
+
#
|
38
|
+
# Parent XML node
|
39
|
+
#
|
40
|
+
# @api private
|
41
|
+
#
|
42
|
+
# @param [Nokogiri::XML::Node]
|
43
|
+
#
|
44
|
+
def __set_parent_node(node)
|
45
|
+
@__parent_node = node
|
46
|
+
end
|
47
|
+
|
48
|
+
#
|
49
|
+
# Initialize container with params
|
50
|
+
#
|
51
|
+
# @api private
|
52
|
+
#
|
53
|
+
# @param [Array<Object>] val
|
54
|
+
#
|
55
|
+
def __initialize_with(val)
|
56
|
+
val.each { |v| new(v) }
|
57
|
+
end
|
58
|
+
|
59
|
+
#
|
60
|
+
# Does this container contain only empty objects?
|
61
|
+
#
|
62
|
+
# @api private
|
63
|
+
#
|
64
|
+
# @return [Boolean]
|
65
|
+
#
|
66
|
+
def __empty?
|
67
|
+
all?(&:__empty?)
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|