ruby-xsd 0.0.2
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.
- data/.gitignore +17 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +29 -0
- data/Rakefile +8 -0
- data/lib/ruby-xsd.rb +20 -0
- data/lib/ruby-xsd/class_maker.rb +149 -0
- data/lib/ruby-xsd/version.rb +5 -0
- data/ruby-xsd.gemspec +24 -0
- data/test/minitest_helper.rb +5 -0
- data/test/ruby-xsd/test.rb +342 -0
- metadata +123 -0
data/.gitignore
ADDED
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
Copyright (c) 2012 Fábio Luiz Nery de Miranda
|
|
2
|
+
|
|
3
|
+
MIT License
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
|
6
|
+
a copy of this software and associated documentation files (the
|
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
|
11
|
+
the following conditions:
|
|
12
|
+
|
|
13
|
+
The above copyright notice and this permission notice shall be
|
|
14
|
+
included in all copies or substantial portions of the Software.
|
|
15
|
+
|
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
# Ruby::Xsd
|
|
2
|
+
|
|
3
|
+
TODO: Write a gem description
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
Add this line to your application's Gemfile:
|
|
8
|
+
|
|
9
|
+
gem 'ruby-xsd'
|
|
10
|
+
|
|
11
|
+
And then execute:
|
|
12
|
+
|
|
13
|
+
$ bundle
|
|
14
|
+
|
|
15
|
+
Or install it yourself as:
|
|
16
|
+
|
|
17
|
+
$ gem install ruby-xsd
|
|
18
|
+
|
|
19
|
+
## Usage
|
|
20
|
+
|
|
21
|
+
TODO: Write usage instructions here
|
|
22
|
+
|
|
23
|
+
## Contributing
|
|
24
|
+
|
|
25
|
+
1. Fork it
|
|
26
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
|
27
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
|
28
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
|
29
|
+
5. Create new Pull Request
|
data/Rakefile
ADDED
data/lib/ruby-xsd.rb
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
require "ruby-xsd/version"
|
|
2
|
+
require "ruby-xsd/class_maker"
|
|
3
|
+
require "nokogiri"
|
|
4
|
+
|
|
5
|
+
class RubyXsd
|
|
6
|
+
class << self
|
|
7
|
+
include ClassMaker
|
|
8
|
+
|
|
9
|
+
def models_from xsd_definitions
|
|
10
|
+
doc = Nokogiri::XML xsd_definitions
|
|
11
|
+
|
|
12
|
+
schema = doc.children.first
|
|
13
|
+
raise "Invalid XMLSchema root" if schema.name != "schema"
|
|
14
|
+
raise "Missing XMLSchema namespace" if schema.namespace.nil?
|
|
15
|
+
raise "Wrong XMLSchema namespace" unless is_xml_schema_node schema
|
|
16
|
+
|
|
17
|
+
schema.children.each { |node| make_definition node }
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
require "active_model"
|
|
2
|
+
require "active_support"
|
|
3
|
+
|
|
4
|
+
module ClassMaker
|
|
5
|
+
include ActiveSupport::Inflector
|
|
6
|
+
|
|
7
|
+
XMLSchemaNS = "http://www.w3.org/2001/XMLSchema"
|
|
8
|
+
|
|
9
|
+
def make_definition node, target=Object
|
|
10
|
+
return if is_text node
|
|
11
|
+
|
|
12
|
+
attrs = node.attributes.to_hash
|
|
13
|
+
name = attrs["name"].value
|
|
14
|
+
if is_element node
|
|
15
|
+
type = attrs["type"].value if attrs.has_key? "type"
|
|
16
|
+
if type.nil?
|
|
17
|
+
complex_node = select_children(node, "complexType").first
|
|
18
|
+
define_class name, complex_node, target
|
|
19
|
+
else
|
|
20
|
+
attr_accessor name
|
|
21
|
+
end
|
|
22
|
+
elsif is_simple node
|
|
23
|
+
if not name.nil?
|
|
24
|
+
restrictions = select_children(node, "restriction").first
|
|
25
|
+
define_validator name, restrictions, target
|
|
26
|
+
end
|
|
27
|
+
elsif is_complex_root node
|
|
28
|
+
define_class name, node, target
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
private
|
|
33
|
+
def namespace_of node
|
|
34
|
+
node.namespace.href
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def is_text node
|
|
38
|
+
node.name == "text"
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def is_xml_schema_node node
|
|
42
|
+
namespace_of(node) == XMLSchemaNS
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
def is_element node
|
|
46
|
+
is_xml_schema_node node and node.name == "element"
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
def is_simple node
|
|
50
|
+
is_xml_schema_node node and node.name == "simpleType"
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
def is_complex_root node
|
|
54
|
+
is_xml_schema_node node and node.name == "complexType"
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
def define_class name, node, target
|
|
58
|
+
name = classify name
|
|
59
|
+
|
|
60
|
+
elems = []
|
|
61
|
+
unless node.nil?
|
|
62
|
+
sequence = select_children node, "sequence"
|
|
63
|
+
elems = select_children sequence.first, "element" unless sequence.empty?
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
cls = Class.new do
|
|
67
|
+
class << self
|
|
68
|
+
include ClassMaker
|
|
69
|
+
end
|
|
70
|
+
elems.each { |e| make_definition e, self }
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
target.const_set name, cls
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
def define_validator name, restrictions, target
|
|
77
|
+
name = classify "#{name}_validator"
|
|
78
|
+
|
|
79
|
+
type = constantize classify restrictions
|
|
80
|
+
.attributes["base"].value.split(":").last
|
|
81
|
+
|
|
82
|
+
ws_action = select_children(restrictions, "whiteSpace").first
|
|
83
|
+
ws_action = ws_action.attributes["value"].value unless ws_action.nil?
|
|
84
|
+
|
|
85
|
+
enum_values = select_children(restrictions, "enumeration").collect { |enum|
|
|
86
|
+
enum.attributes["value"].value
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
pattern = select_children(restrictions, "pattern").first
|
|
90
|
+
pattern = pattern.attributes["value"].value unless pattern.nil?
|
|
91
|
+
|
|
92
|
+
cls = Class.new ActiveModel::EachValidator do
|
|
93
|
+
const_set "TYPE", type
|
|
94
|
+
const_set("WS_ACTION", ws_action) unless ws_action.nil?
|
|
95
|
+
const_set "ENUM_VALUES", enum_values
|
|
96
|
+
unless pattern.nil?
|
|
97
|
+
const_set "PATTERN", pattern
|
|
98
|
+
const_set "REGEXP", Regexp.new("^#{pattern}$")
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
def validate_each record, attribute, value
|
|
102
|
+
validate_type record, attribute, value
|
|
103
|
+
handle_whitespaces record, attribute, value
|
|
104
|
+
validate_enumeration record, attribute, value unless self.class::ENUM_VALUES.empty?
|
|
105
|
+
validate_regexp record, attribute, value if self.class.const_defined? "REGEXP"
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
private
|
|
109
|
+
def validate_type record, attribute, value
|
|
110
|
+
unless value.kind_of? self.class::TYPE
|
|
111
|
+
add_error record, attribute, "#{value}: not a #{self.class::TYPE}"
|
|
112
|
+
end
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
def handle_whitespaces record, attribute, value
|
|
116
|
+
if self.class.const_defined? "WS_ACTION"
|
|
117
|
+
case self.class::WS_ACTION
|
|
118
|
+
when "replace" then value.gsub! /[\n\t\r ]/, " "
|
|
119
|
+
when "collapse" then
|
|
120
|
+
value.gsub! /[\n\t\r]/, " "
|
|
121
|
+
value = value.split.join " "
|
|
122
|
+
end
|
|
123
|
+
record.send "#{attribute}=", value
|
|
124
|
+
end
|
|
125
|
+
end
|
|
126
|
+
|
|
127
|
+
def validate_enumeration record, attribute, value
|
|
128
|
+
unless self.class::ENUM_VALUES.include? value.to_s
|
|
129
|
+
add_error record, attribute, "#{value}: not in #{self.class::ENUM_VALUES}"
|
|
130
|
+
end
|
|
131
|
+
end
|
|
132
|
+
|
|
133
|
+
def validate_regexp record, attribute, value
|
|
134
|
+
unless value =~ self.class::REGEXP
|
|
135
|
+
add_error record, attribute, "#{value}: not matching #{self.class::PATTERN}"
|
|
136
|
+
end
|
|
137
|
+
end
|
|
138
|
+
|
|
139
|
+
def add_error record, attribute, message=""
|
|
140
|
+
record.errors[attribute] << (options[:message] || message)
|
|
141
|
+
end
|
|
142
|
+
end
|
|
143
|
+
target.const_set name, cls
|
|
144
|
+
end
|
|
145
|
+
|
|
146
|
+
def select_children node, name
|
|
147
|
+
node.children.select { |n| n.name == name }
|
|
148
|
+
end
|
|
149
|
+
end
|
data/ruby-xsd.gemspec
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
|
4
|
+
require 'ruby-xsd/version'
|
|
5
|
+
|
|
6
|
+
Gem::Specification.new do |gem|
|
|
7
|
+
gem.name = "ruby-xsd"
|
|
8
|
+
gem.version = Ruby::Xsd::VERSION
|
|
9
|
+
gem.authors = ["Fábio Luiz Nery de Miranda"]
|
|
10
|
+
gem.email = ["fabio@miranti.net.br"]
|
|
11
|
+
gem.description = %q{Generates in-memory ruby classes from XSD files}
|
|
12
|
+
gem.summary = %q{}
|
|
13
|
+
gem.homepage = "https://github.com/fabiolnm/ruby-xsd"
|
|
14
|
+
|
|
15
|
+
gem.files = `git ls-files`.split($/)
|
|
16
|
+
gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
|
|
17
|
+
gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
|
|
18
|
+
gem.require_paths = ["lib"]
|
|
19
|
+
|
|
20
|
+
gem.add_development_dependency "debugger"
|
|
21
|
+
gem.add_development_dependency "nokogiri"
|
|
22
|
+
gem.add_development_dependency "activesupport"
|
|
23
|
+
gem.add_development_dependency "activemodel"
|
|
24
|
+
end
|
|
@@ -0,0 +1,342 @@
|
|
|
1
|
+
describe RubyXsd do
|
|
2
|
+
describe "XMLSchema root validation" do
|
|
3
|
+
it "rejects non-schema root" do
|
|
4
|
+
ex = assert_raises RuntimeError do
|
|
5
|
+
RubyXsd.models_from "<non-xs></non-xs>"
|
|
6
|
+
end
|
|
7
|
+
assert_equal "Invalid XMLSchema root", ex.message
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
it "rejects schema root without XMLSchema namespace" do
|
|
11
|
+
ex = assert_raises RuntimeError do
|
|
12
|
+
RubyXsd.models_from "<schema></schema>"
|
|
13
|
+
end
|
|
14
|
+
assert_equal "Missing XMLSchema namespace", ex.message
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
it "rejects schema with wrong XMLSchema namespace" do
|
|
18
|
+
ex = assert_raises RuntimeError do
|
|
19
|
+
RubyXsd.models_from "<xs:schema xmlns:xs='wrong'></xs:schema>"
|
|
20
|
+
end
|
|
21
|
+
assert_equal "Wrong XMLSchema namespace", ex.message
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
let(:schema) {
|
|
26
|
+
"<xs:schema xmlns:xs='#{ClassMaker::XMLSchemaNS}'>%s</xs:schema>"
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
describe "simple elements" do
|
|
30
|
+
let(:template) {
|
|
31
|
+
schema % "<xs:element name='%s' type='%s' />"
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
it "defines object attributes" do
|
|
35
|
+
RubyXsd.models_from template % [ "xsd_attr", "xs:string" ]
|
|
36
|
+
RubyXsd.new.must_respond_to :xsd_attr
|
|
37
|
+
RubyXsd.new.must_respond_to :xsd_attr=
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
describe "complex elements" do
|
|
42
|
+
let(:template) {
|
|
43
|
+
schema % "<xs:element name='%s'>%s</xs:element>"
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
let(:class_template) {
|
|
47
|
+
template % [ "xsd_complex", "" ]
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
let(:class_with_attrs_template) {
|
|
51
|
+
template % [ "xsd_complex_with_attr", %{
|
|
52
|
+
<xs:complexType>
|
|
53
|
+
<xs:sequence>
|
|
54
|
+
<xs:element name="foo" type="xs:string" />
|
|
55
|
+
<xs:element name="bar" type="xs:string" />
|
|
56
|
+
</xs:sequence>
|
|
57
|
+
</xs:complexType>
|
|
58
|
+
}]
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
it "defines a new Class" do
|
|
62
|
+
RubyXsd.models_from class_template
|
|
63
|
+
defined?(XsdComplex).must_be :==, "constant"
|
|
64
|
+
XsdComplex.class.must_be :==, Class
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
it "defines class attributes" do
|
|
68
|
+
RubyXsd.models_from class_with_attrs_template
|
|
69
|
+
|
|
70
|
+
defined?(XsdComplexWithAttr).must_be :==, "constant"
|
|
71
|
+
XsdComplexWithAttr.class.must_be :==, Class
|
|
72
|
+
|
|
73
|
+
obj = XsdComplexWithAttr.new
|
|
74
|
+
[ :foo, :foo=, :bar, :bar= ].each { |m|
|
|
75
|
+
obj.must_respond_to m
|
|
76
|
+
}
|
|
77
|
+
end
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
describe "complex roots" do
|
|
81
|
+
let(:template) {
|
|
82
|
+
schema % "<xs:complexType name='%s'>%s</xs:complexType>"
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
let(:complex_root) {
|
|
86
|
+
template % [ "complex_root", "" ]
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
let(:root_with_attrs_template) {
|
|
90
|
+
template % [ "xsd_root_with_attr", %{
|
|
91
|
+
<xs:sequence>
|
|
92
|
+
<xs:element name="foo" type="xs:string" />
|
|
93
|
+
<xs:element name="bar" type="xs:string" />
|
|
94
|
+
</xs:sequence>
|
|
95
|
+
}]
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
it "defines new class" do
|
|
99
|
+
RubyXsd.models_from complex_root
|
|
100
|
+
defined?(ComplexRoot).must_be :==, "constant"
|
|
101
|
+
ComplexRoot.class.must_be :==, Class
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
it "defines class attributes" do
|
|
105
|
+
RubyXsd.models_from root_with_attrs_template
|
|
106
|
+
|
|
107
|
+
defined?(XsdRootWithAttr).must_be :==, "constant"
|
|
108
|
+
XsdRootWithAttr.class.must_be :==, Class
|
|
109
|
+
|
|
110
|
+
obj = XsdRootWithAttr.new
|
|
111
|
+
[ :foo, :foo=, :bar, :bar= ].each { |m|
|
|
112
|
+
obj.must_respond_to m
|
|
113
|
+
}
|
|
114
|
+
end
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
describe "nested classes" do
|
|
118
|
+
let(:template) {
|
|
119
|
+
schema % %{
|
|
120
|
+
<xs:complexType name='%s'>
|
|
121
|
+
<xs:sequence>%s</xs:sequence>
|
|
122
|
+
</xs:complexType>
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
let(:elements_template) {
|
|
127
|
+
template % [ "elem_parent", %{
|
|
128
|
+
<xs:element name="nested1"></xs:element>
|
|
129
|
+
<xs:element name="nested2"></xs:element>
|
|
130
|
+
}]
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
let(:elements_template_with_attr) {
|
|
134
|
+
template % [ "elem_parent_with_attr", %{
|
|
135
|
+
<xs:element name="nested1">
|
|
136
|
+
<xs:complexType>
|
|
137
|
+
<xs:sequence>
|
|
138
|
+
<xs:element name="foo" type="xs:string" />
|
|
139
|
+
</xs:sequence>
|
|
140
|
+
</xs:complexType>
|
|
141
|
+
</xs:element>
|
|
142
|
+
<xs:element name="nested2">
|
|
143
|
+
<xs:complexType>
|
|
144
|
+
<xs:sequence>
|
|
145
|
+
<xs:element name="bar" type="xs:string" />
|
|
146
|
+
</xs:sequence>
|
|
147
|
+
</xs:complexType>
|
|
148
|
+
</xs:element>
|
|
149
|
+
}]
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
it "nests with complex elements" do
|
|
153
|
+
RubyXsd.models_from elements_template
|
|
154
|
+
|
|
155
|
+
defined?(ElemParent).must_be :==, "constant"
|
|
156
|
+
ElemParent.class.must_be :==, Class
|
|
157
|
+
|
|
158
|
+
defined?(Nested1).must_be_nil
|
|
159
|
+
defined?(ElemParent::Nested1).must_be :==, "constant"
|
|
160
|
+
ElemParent::Nested1.class.must_be :==, Class
|
|
161
|
+
|
|
162
|
+
defined?(Nested2).must_be_nil
|
|
163
|
+
defined?(ElemParent::Nested2).must_be :==, "constant"
|
|
164
|
+
ElemParent::Nested2.class.must_be :==, Class
|
|
165
|
+
end
|
|
166
|
+
|
|
167
|
+
it "nests with complex elements" do
|
|
168
|
+
RubyXsd.models_from elements_template_with_attr
|
|
169
|
+
|
|
170
|
+
ElemParentWithAttr::Nested1.new.must_respond_to :foo
|
|
171
|
+
ElemParentWithAttr::Nested1.new.wont_respond_to :bar
|
|
172
|
+
|
|
173
|
+
ElemParentWithAttr::Nested2.new.wont_respond_to :foo
|
|
174
|
+
ElemParentWithAttr::Nested2.new.must_respond_to :bar
|
|
175
|
+
end
|
|
176
|
+
end
|
|
177
|
+
|
|
178
|
+
describe "restrictions" do
|
|
179
|
+
describe "compact form" do
|
|
180
|
+
let(:template) {
|
|
181
|
+
schema % %{
|
|
182
|
+
<xs:simpleType name="foo">
|
|
183
|
+
<xs:restriction base="xs:%s">%s</xs:restriction>
|
|
184
|
+
</xs:simpleType>
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
let(:make_bar) {
|
|
189
|
+
class Bar
|
|
190
|
+
include ActiveModel::Validations
|
|
191
|
+
attr_accessor :baz
|
|
192
|
+
validates :baz, foo: true
|
|
193
|
+
end
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
after do
|
|
197
|
+
[ :FooValidator, :Bar ].each { |const|
|
|
198
|
+
Object.send(:remove_const, const) if Object.const_defined? const
|
|
199
|
+
}
|
|
200
|
+
end
|
|
201
|
+
|
|
202
|
+
it "creates validator" do
|
|
203
|
+
RubyXsd.models_from template % [ "string", "" ]
|
|
204
|
+
|
|
205
|
+
defined?(FooValidator).must_be :==, "constant"
|
|
206
|
+
FooValidator.superclass.must_be :==, ActiveModel::EachValidator
|
|
207
|
+
end
|
|
208
|
+
|
|
209
|
+
it "validates string type" do
|
|
210
|
+
RubyXsd.models_from template % [ "string", "" ]
|
|
211
|
+
make_bar
|
|
212
|
+
|
|
213
|
+
bar = Bar.new
|
|
214
|
+
bar.baz = 1
|
|
215
|
+
bar.valid?.wont_equal true
|
|
216
|
+
|
|
217
|
+
bar.baz = "1"
|
|
218
|
+
bar.valid?.must_equal true
|
|
219
|
+
end
|
|
220
|
+
|
|
221
|
+
it "validates integer type" do
|
|
222
|
+
RubyXsd.models_from template % [ "integer", "" ]
|
|
223
|
+
make_bar
|
|
224
|
+
|
|
225
|
+
bar = Bar.new
|
|
226
|
+
bar.baz = 1
|
|
227
|
+
bar.valid?.must_equal true
|
|
228
|
+
|
|
229
|
+
bar.baz = "1"
|
|
230
|
+
bar.valid?.wont_equal true
|
|
231
|
+
end
|
|
232
|
+
|
|
233
|
+
describe "Whitespace handling" do
|
|
234
|
+
let(:whitespace_schema) {
|
|
235
|
+
template % [ "string", %{<xs:whiteSpace value="%s" />} ]
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
let(:whitespace_string) {
|
|
239
|
+
" abc de\tfg\n\rhi jk "
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
let(:replaced_string) {
|
|
243
|
+
" abc de fg hi jk "
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
let(:collapsed_string) {
|
|
247
|
+
"abc de fg hi jk"
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
def apply action
|
|
251
|
+
xsd = whitespace_schema % action
|
|
252
|
+
RubyXsd.models_from xsd
|
|
253
|
+
make_bar
|
|
254
|
+
|
|
255
|
+
bar = Bar.new
|
|
256
|
+
bar.baz = whitespace_string
|
|
257
|
+
bar.valid?
|
|
258
|
+
bar
|
|
259
|
+
end
|
|
260
|
+
|
|
261
|
+
it "preserves" do
|
|
262
|
+
apply("preserve").baz.must_equal whitespace_string
|
|
263
|
+
end
|
|
264
|
+
|
|
265
|
+
it "replaces" do
|
|
266
|
+
apply("replace").baz.must_equal replaced_string
|
|
267
|
+
end
|
|
268
|
+
|
|
269
|
+
it "collapses" do
|
|
270
|
+
apply("collapse").baz.must_equal collapsed_string
|
|
271
|
+
end
|
|
272
|
+
end
|
|
273
|
+
|
|
274
|
+
describe "Enumeration handling" do
|
|
275
|
+
def enum_xsd values
|
|
276
|
+
enum_str = ""
|
|
277
|
+
values.each do |v|
|
|
278
|
+
enum_str << %{<xs:enumeration value="#{v}" />}
|
|
279
|
+
end
|
|
280
|
+
template % [ "string", enum_str ]
|
|
281
|
+
end
|
|
282
|
+
|
|
283
|
+
let(:range) { (5..10).to_a + (20..25).to_a }
|
|
284
|
+
let(:out_of_range) { (1..30).to_a - range }
|
|
285
|
+
let(:bar) { Bar.new }
|
|
286
|
+
|
|
287
|
+
before do
|
|
288
|
+
RubyXsd.models_from enum_xsd range
|
|
289
|
+
make_bar
|
|
290
|
+
end
|
|
291
|
+
|
|
292
|
+
it "accepts value in range" do
|
|
293
|
+
range.each { |val|
|
|
294
|
+
bar.baz = val.to_s
|
|
295
|
+
bar.valid?.must_equal true, message: bar.errors.messages
|
|
296
|
+
}
|
|
297
|
+
end
|
|
298
|
+
|
|
299
|
+
it "rejects value out of range" do
|
|
300
|
+
out_of_range.each { |val|
|
|
301
|
+
bar.baz = val.to_s
|
|
302
|
+
bar.valid?.wont_equal true, message: bar.errors.messages
|
|
303
|
+
|
|
304
|
+
range_str = range.collect{|v| v.to_s}.to_s
|
|
305
|
+
bar.errors.messages[:baz].first
|
|
306
|
+
.must_equal "#{val}: not in #{range_str}"
|
|
307
|
+
}
|
|
308
|
+
end
|
|
309
|
+
end
|
|
310
|
+
|
|
311
|
+
describe "Regexp handling" do
|
|
312
|
+
let(:pattern) { '\w{3}[X-Z]{3}_\d{6}' }
|
|
313
|
+
|
|
314
|
+
let(:pattern_schema) {
|
|
315
|
+
template % [ "string", %{<xs:pattern value="#{pattern}" />} ]
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
let(:bar) {
|
|
319
|
+
inst = Bar.new
|
|
320
|
+
inst.baz = "AbcXYZ_123456"
|
|
321
|
+
inst
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
before do
|
|
325
|
+
RubyXsd.models_from pattern_schema
|
|
326
|
+
make_bar
|
|
327
|
+
end
|
|
328
|
+
|
|
329
|
+
it "accepts value matching pattern" do
|
|
330
|
+
bar.valid?.must_equal true, message: bar.errors.messages
|
|
331
|
+
end
|
|
332
|
+
|
|
333
|
+
it "rejects value not matching pattern" do
|
|
334
|
+
bar.baz = "not matches"
|
|
335
|
+
bar.valid?.wont_equal true, message: bar.errors.messages
|
|
336
|
+
bar.errors.messages[:baz].first
|
|
337
|
+
.must_equal "#{bar.baz}: not matching #{pattern}"
|
|
338
|
+
end
|
|
339
|
+
end
|
|
340
|
+
end
|
|
341
|
+
end
|
|
342
|
+
end
|
metadata
ADDED
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
|
2
|
+
name: ruby-xsd
|
|
3
|
+
version: !ruby/object:Gem::Version
|
|
4
|
+
version: 0.0.2
|
|
5
|
+
prerelease:
|
|
6
|
+
platform: ruby
|
|
7
|
+
authors:
|
|
8
|
+
- Fábio Luiz Nery de Miranda
|
|
9
|
+
autorequire:
|
|
10
|
+
bindir: bin
|
|
11
|
+
cert_chain: []
|
|
12
|
+
date: 2012-10-19 00:00:00.000000000 Z
|
|
13
|
+
dependencies:
|
|
14
|
+
- !ruby/object:Gem::Dependency
|
|
15
|
+
name: debugger
|
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
|
17
|
+
none: false
|
|
18
|
+
requirements:
|
|
19
|
+
- - ! '>='
|
|
20
|
+
- !ruby/object:Gem::Version
|
|
21
|
+
version: '0'
|
|
22
|
+
type: :development
|
|
23
|
+
prerelease: false
|
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
25
|
+
none: false
|
|
26
|
+
requirements:
|
|
27
|
+
- - ! '>='
|
|
28
|
+
- !ruby/object:Gem::Version
|
|
29
|
+
version: '0'
|
|
30
|
+
- !ruby/object:Gem::Dependency
|
|
31
|
+
name: nokogiri
|
|
32
|
+
requirement: !ruby/object:Gem::Requirement
|
|
33
|
+
none: false
|
|
34
|
+
requirements:
|
|
35
|
+
- - ! '>='
|
|
36
|
+
- !ruby/object:Gem::Version
|
|
37
|
+
version: '0'
|
|
38
|
+
type: :development
|
|
39
|
+
prerelease: false
|
|
40
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
41
|
+
none: false
|
|
42
|
+
requirements:
|
|
43
|
+
- - ! '>='
|
|
44
|
+
- !ruby/object:Gem::Version
|
|
45
|
+
version: '0'
|
|
46
|
+
- !ruby/object:Gem::Dependency
|
|
47
|
+
name: activesupport
|
|
48
|
+
requirement: !ruby/object:Gem::Requirement
|
|
49
|
+
none: false
|
|
50
|
+
requirements:
|
|
51
|
+
- - ! '>='
|
|
52
|
+
- !ruby/object:Gem::Version
|
|
53
|
+
version: '0'
|
|
54
|
+
type: :development
|
|
55
|
+
prerelease: false
|
|
56
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
57
|
+
none: false
|
|
58
|
+
requirements:
|
|
59
|
+
- - ! '>='
|
|
60
|
+
- !ruby/object:Gem::Version
|
|
61
|
+
version: '0'
|
|
62
|
+
- !ruby/object:Gem::Dependency
|
|
63
|
+
name: activemodel
|
|
64
|
+
requirement: !ruby/object:Gem::Requirement
|
|
65
|
+
none: false
|
|
66
|
+
requirements:
|
|
67
|
+
- - ! '>='
|
|
68
|
+
- !ruby/object:Gem::Version
|
|
69
|
+
version: '0'
|
|
70
|
+
type: :development
|
|
71
|
+
prerelease: false
|
|
72
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
73
|
+
none: false
|
|
74
|
+
requirements:
|
|
75
|
+
- - ! '>='
|
|
76
|
+
- !ruby/object:Gem::Version
|
|
77
|
+
version: '0'
|
|
78
|
+
description: Generates in-memory ruby classes from XSD files
|
|
79
|
+
email:
|
|
80
|
+
- fabio@miranti.net.br
|
|
81
|
+
executables: []
|
|
82
|
+
extensions: []
|
|
83
|
+
extra_rdoc_files: []
|
|
84
|
+
files:
|
|
85
|
+
- .gitignore
|
|
86
|
+
- Gemfile
|
|
87
|
+
- LICENSE.txt
|
|
88
|
+
- README.md
|
|
89
|
+
- Rakefile
|
|
90
|
+
- lib/ruby-xsd.rb
|
|
91
|
+
- lib/ruby-xsd/class_maker.rb
|
|
92
|
+
- lib/ruby-xsd/version.rb
|
|
93
|
+
- ruby-xsd.gemspec
|
|
94
|
+
- test/minitest_helper.rb
|
|
95
|
+
- test/ruby-xsd/test.rb
|
|
96
|
+
homepage: https://github.com/fabiolnm/ruby-xsd
|
|
97
|
+
licenses: []
|
|
98
|
+
post_install_message:
|
|
99
|
+
rdoc_options: []
|
|
100
|
+
require_paths:
|
|
101
|
+
- lib
|
|
102
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
|
103
|
+
none: false
|
|
104
|
+
requirements:
|
|
105
|
+
- - ! '>='
|
|
106
|
+
- !ruby/object:Gem::Version
|
|
107
|
+
version: '0'
|
|
108
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
109
|
+
none: false
|
|
110
|
+
requirements:
|
|
111
|
+
- - ! '>='
|
|
112
|
+
- !ruby/object:Gem::Version
|
|
113
|
+
version: '0'
|
|
114
|
+
requirements: []
|
|
115
|
+
rubyforge_project:
|
|
116
|
+
rubygems_version: 1.8.24
|
|
117
|
+
signing_key:
|
|
118
|
+
specification_version: 3
|
|
119
|
+
summary: ''
|
|
120
|
+
test_files:
|
|
121
|
+
- test/minitest_helper.rb
|
|
122
|
+
- test/ruby-xsd/test.rb
|
|
123
|
+
has_rdoc:
|