ruby-xsd 0.0.2
Sign up to get free protection for your applications and to get access to all the features.
- 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:
|