jaxb2ruby 0.0.1-java
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/bin/jaxb2ruby +90 -0
- data/lib/jaxb2ruby.rb +15 -0
- data/lib/jaxb2ruby/classes.rb +184 -0
- data/lib/jaxb2ruby/config.xjb +16 -0
- data/lib/jaxb2ruby/converter.rb +250 -0
- data/lib/jaxb2ruby/template.rb +33 -0
- data/lib/jaxb2ruby/type_util.rb +90 -0
- data/lib/jaxb2ruby/version.rb +3 -0
- data/lib/jaxb2ruby/xjc.rb +59 -0
- data/lib/templates/happymapper.erb +39 -0
- data/lib/templates/roxml.erb +42 -0
- data/lib/templates/ruby.erb +44 -0
- data/lib/templates/util/happymapper.rb +26 -0
- data/lib/templates/util/roxml.rb +29 -0
- data/spec/converter_spec.rb +213 -0
- data/spec/spec_helper.rb +25 -0
- data/spec/template_spec.rb +128 -0
- metadata +113 -0
@@ -0,0 +1,33 @@
|
|
1
|
+
require "erb"
|
2
|
+
|
3
|
+
module JAXB2Ruby
|
4
|
+
class Template # :nodoc:
|
5
|
+
HEADING=<<HEAD
|
6
|
+
#
|
7
|
+
# Auto-generated by jaxb2ruby v<%= VERSION %> on <%= Time.now %>
|
8
|
+
# https://github.com/sshaw/jaxb2ruby
|
9
|
+
#
|
10
|
+
HEAD
|
11
|
+
|
12
|
+
PATHS = Hash[
|
13
|
+
Dir[File.expand_path(__FILE__ + "/../../templates/*.erb")].map do |path|
|
14
|
+
[File.basename(path, ".erb"), path]
|
15
|
+
end
|
16
|
+
]
|
17
|
+
|
18
|
+
DEFAULT = PATHS["roxml"]
|
19
|
+
|
20
|
+
def initialize(name = nil)
|
21
|
+
# If it's not a named template assume it's a path
|
22
|
+
path = PATHS[name] || name || DEFAULT
|
23
|
+
@__erb = ERB.new(HEADING + File.read(path), nil, "<>%-")
|
24
|
+
rescue => e
|
25
|
+
raise Error, "cannot load class template: #{e}"
|
26
|
+
end
|
27
|
+
|
28
|
+
def build(klass)
|
29
|
+
@class = klass
|
30
|
+
@__erb.result(binding)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,90 @@
|
|
1
|
+
module JAXB2Ruby
|
2
|
+
class TypeUtil # :nodoc:
|
3
|
+
# Only includes types that aren't annotated with @XmlSchemaType
|
4
|
+
JAVA_TO_SCHEMA = {
|
5
|
+
"java.lang.Boolean" => "boolean",
|
6
|
+
"boolean" => "boolean",
|
7
|
+
"byte" => "byte",
|
8
|
+
# byte[]
|
9
|
+
"[B" => "base64Binary",
|
10
|
+
"double" => "double",
|
11
|
+
"float" => "float",
|
12
|
+
"java.lang.Integer" => "int",
|
13
|
+
"int" => "int",
|
14
|
+
"java.lang.Object" => "anySimpleType",
|
15
|
+
"java.lang.String" => "string",
|
16
|
+
"java.math.BigDecimal" => "decimal",
|
17
|
+
"java.math.BigInteger" => "int",
|
18
|
+
"javax.xml.datatype.Duration" => "duration",
|
19
|
+
"javax.xml.datatype.XMLGregorianCalendar" => "dateTime",
|
20
|
+
#"javax.xml.namespace.QName" => "NOTATION"
|
21
|
+
"javax.xml.namespace.QName" => "QName",
|
22
|
+
"java.lang.Long" => "long",
|
23
|
+
"long" => "long",
|
24
|
+
"short" => "short"
|
25
|
+
}
|
26
|
+
|
27
|
+
SCHEMA_TO_RUBY = {
|
28
|
+
"ID" => :ID,
|
29
|
+
"IDREF" => :IDREF,
|
30
|
+
"Name" => "String",
|
31
|
+
"NCName" => "String",
|
32
|
+
"NMTOKEN" => "String",
|
33
|
+
"anySimpleType" => "Object",
|
34
|
+
"anyType" => "Object",
|
35
|
+
"anyURI" => "String",
|
36
|
+
"base64Binary" => "String",
|
37
|
+
"boolean" => :boolean,
|
38
|
+
"byte" => "Integer",
|
39
|
+
"date" => "Date",
|
40
|
+
"dateTime" => "DateTime",
|
41
|
+
"decimal" => "Float", # BigDecimal
|
42
|
+
"double" => "Float",
|
43
|
+
"duration" => "String",
|
44
|
+
"float" => "Float",
|
45
|
+
"gDay" => "String",
|
46
|
+
"gMonth" => "String",
|
47
|
+
"gMonthDay" => "String",
|
48
|
+
"gYear" => "String",
|
49
|
+
"gYearMonth" => "String",
|
50
|
+
"hexBinary" => "String",
|
51
|
+
"int" => "Integer",
|
52
|
+
"integer" => "Integer",
|
53
|
+
"long" => "Integer",
|
54
|
+
"language" => "String",
|
55
|
+
"nonNegativeInteger" => "Integer",
|
56
|
+
"nonPositiveInteger" => "Integer",
|
57
|
+
"normalizedString" => "String",
|
58
|
+
"positiveInteger" => "Integer",
|
59
|
+
"QName" => "String",
|
60
|
+
"short" => "Integer",
|
61
|
+
"string" => "String",
|
62
|
+
"time" => "Time",
|
63
|
+
"token" => "String",
|
64
|
+
"unsignedByte" => "Integer",
|
65
|
+
"unsignedInt" => "Integer",
|
66
|
+
"unsignedLong" => "Integer",
|
67
|
+
"unsignedShort" => "Integer"
|
68
|
+
}
|
69
|
+
|
70
|
+
def initialize(schema2ruby)
|
71
|
+
@schema2ruby = SCHEMA_TO_RUBY.merge(schema2ruby || {})
|
72
|
+
end
|
73
|
+
|
74
|
+
def schema_ruby_types
|
75
|
+
@schema_types ||= SCHEMA_TO_RUBY.values.uniq
|
76
|
+
end
|
77
|
+
|
78
|
+
def java2schema(klass)
|
79
|
+
JAVA_TO_SCHEMA[klass]
|
80
|
+
end
|
81
|
+
|
82
|
+
def schema2ruby(type)
|
83
|
+
@schema2ruby[type]
|
84
|
+
end
|
85
|
+
|
86
|
+
def java2ruby(klass)
|
87
|
+
schema2ruby(java2schema(klass))
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
@@ -0,0 +1,59 @@
|
|
1
|
+
require "tmpdir"
|
2
|
+
require "cocaine"
|
3
|
+
|
4
|
+
module JAXB2Ruby
|
5
|
+
class XJC # :nodoc:
|
6
|
+
CONFIG = File.join(File.dirname(__FILE__), "config.xjb")
|
7
|
+
|
8
|
+
# https://github.com/thoughtbot/cocaine/issues/24
|
9
|
+
Cocaine::CommandLine.runner = Cocaine::CommandLine::BackticksRunner.new
|
10
|
+
|
11
|
+
def initialize(schema, options = {})
|
12
|
+
@schema = schema
|
13
|
+
@options = options
|
14
|
+
setup_tmpdirs
|
15
|
+
end
|
16
|
+
|
17
|
+
def execute
|
18
|
+
xjc
|
19
|
+
javac
|
20
|
+
@classes
|
21
|
+
end
|
22
|
+
|
23
|
+
private
|
24
|
+
def setup_tmpdirs
|
25
|
+
@tmproot = Dir.mktmpdir
|
26
|
+
@classes = File.join(@tmproot, "classes")
|
27
|
+
@sources = File.join(@tmproot, "source")
|
28
|
+
[@classes, @sources].each { |dir| Dir.mkdir(dir) }
|
29
|
+
rescue IOErorr, SystemCallError => e
|
30
|
+
raise Error, "error creating temp directories: #{e}"
|
31
|
+
end
|
32
|
+
|
33
|
+
def xjc
|
34
|
+
options = @schema.end_with?(".wsdl") || @options[:wsdl] ? "-wsdl " : ""
|
35
|
+
options << "-extension -npa -d :sources :schema -b :config"
|
36
|
+
options << @options[:jvm].map { |opt| " -J#{opt}" }.join(" ") if @options[:jvm]
|
37
|
+
line = Cocaine::CommandLine.new("xjc", options)
|
38
|
+
line.run(:schema => @schema, :sources => @sources, :config => CONFIG)
|
39
|
+
rescue Cocaine::ExitStatusError => e
|
40
|
+
raise Error, "xjc execution failed: #{e}"
|
41
|
+
rescue Cocaine::CommandNotFoundError => e
|
42
|
+
raise command_not_found("xjc")
|
43
|
+
end
|
44
|
+
|
45
|
+
def javac
|
46
|
+
files = Dir[ File.join(@sources, "**/*.java") ]
|
47
|
+
line = Cocaine::CommandLine.new("javac", "-d :classes :files")
|
48
|
+
line.run(:classes => @classes, :files => files)
|
49
|
+
rescue Cocaine::ExitStatusError => e
|
50
|
+
raise Error, "javac execution failed: #{e}"
|
51
|
+
rescue Cocaine::CommandNotFoundError => e
|
52
|
+
raise command_not_found("javac")
|
53
|
+
end
|
54
|
+
|
55
|
+
def command_not_found(cmd)
|
56
|
+
Error.new("#{cmd} command not found, is it in your PATH enviornment variable?")
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
<%- require "templates/util/happymapper" -%>
|
2
|
+
|
3
|
+
require "happymapper"
|
4
|
+
<%- @class.requires.each do |mod| -%>
|
5
|
+
require "<%= mod %>"
|
6
|
+
<%- end -%>
|
7
|
+
|
8
|
+
<%= @class.module.map { |mod| "module #{mod}" }.join " " %>
|
9
|
+
<%= @class.outter_class.map { |klass| "class #{klass}" }.join "; " %>
|
10
|
+
|
11
|
+
class <%= @class.basename %> <%= "< #{@class.superclass}" if @class.superclass %>
|
12
|
+
include HappyMapper
|
13
|
+
|
14
|
+
<%- [@class.element].concat(@class.element.children).map { |e| e.namespace }.compact.uniq.each do |ns| -%>
|
15
|
+
register_namespace "<%= ns.prefix %>", "<%= ns %>"
|
16
|
+
<%- end -%>
|
17
|
+
|
18
|
+
<%- if @class.element.root? && @class.element.namespace -%>
|
19
|
+
namespace "<%= @class.element.namespace.prefix %>"
|
20
|
+
<%- end -%>
|
21
|
+
|
22
|
+
tag "<%= @class.element.local_name %>"
|
23
|
+
|
24
|
+
<%- @class.element.children.each do |e| -%>
|
25
|
+
<% next if e.type == :ID || e.type == :IDREF %>
|
26
|
+
<%= accessor_method(e) %> :<%= e.accessor %>, <%= type_name(e) %>, :tag => "<%= e.local_name %>", :namespace => <%= namespace(e.namespace) %>
|
27
|
+
<%- end -%>
|
28
|
+
|
29
|
+
<%- if @class.element.text? -%>
|
30
|
+
content :content
|
31
|
+
<%- end -%>
|
32
|
+
|
33
|
+
<% @class.element.attributes.each do |attr| %>
|
34
|
+
attribute :<%= attr.accessor %>, <%= type_name(attr) %>, :tag => "<%= attr.local_name %>", :namespace => <%= namespace(attr.namespace) %>
|
35
|
+
<% end %>
|
36
|
+
end
|
37
|
+
|
38
|
+
<%= @class.outter_class.map { "end" }.join " " %>
|
39
|
+
<%= @class.module.map { "end" }.join " " %>
|
@@ -0,0 +1,42 @@
|
|
1
|
+
<%- require "templates/util/roxml" -%>
|
2
|
+
|
3
|
+
require "roxml"
|
4
|
+
<%- @class.requires.each do |mod| -%>
|
5
|
+
require "<%= mod %>"
|
6
|
+
<%- end -%>
|
7
|
+
|
8
|
+
<%= @class.module.map { |mod| "module #{mod}" }.join " " %>
|
9
|
+
<%= @class.outter_class.map { |klass| "class #{klass}" }.join "; " %>
|
10
|
+
|
11
|
+
class <%= @class.basename %> <%= "< #{@class.superclass}" if @class.superclass %>
|
12
|
+
include ROXML
|
13
|
+
|
14
|
+
<%= namespace_map(@class) %>
|
15
|
+
|
16
|
+
xml_name "<%= @class.element.name %>"
|
17
|
+
|
18
|
+
<%- @class.element.children.each do |e| -%>
|
19
|
+
<% if e.array? %>
|
20
|
+
xml_accessor <%= accessor_name(e) %>, :as => <%= type_name(e) %>, :from => "<%= e.name %>", :required => <%= e.required? %>
|
21
|
+
<%- elsif unsupported_type?(e.type) -%>
|
22
|
+
xml_accessor <%= accessor_name(e) %>, :from => "<%= e.name %>", :required => <%= e.required? %>
|
23
|
+
<%- else -%>
|
24
|
+
xml_accessor <%= accessor_name(e) %>, :as => <%= type_name(e) %>, :from => "<%= e.name %>", :required => <%= e.required? %>
|
25
|
+
<%- end -%>
|
26
|
+
<%- end -%>
|
27
|
+
|
28
|
+
<%- if @class.element.text? -%>
|
29
|
+
xml_accessor :content, :from => ".", :required => <%= @class.element.required? %>
|
30
|
+
<%- end -%>
|
31
|
+
|
32
|
+
<% @class.element.attributes.each do |attr| %>
|
33
|
+
<%- if unsupported_type?(attr.type) -%>
|
34
|
+
xml_accessor <%= accessor_name(attr) %>, :from => "@<%= attr.name %>", :required => <%= attr.required? %>
|
35
|
+
<% else %>
|
36
|
+
xml_accessor <%= accessor_name(attr) %>, :as => <%= type_name(attr) %>, :from => "@<%= attr.name %>", :required => <%= attr.required? %>
|
37
|
+
<% end %>
|
38
|
+
<% end %>
|
39
|
+
end
|
40
|
+
|
41
|
+
<%= @class.outter_class.map { "end" }.join " " %>
|
42
|
+
<%= @class.module.map { "end" }.join " " %>
|
@@ -0,0 +1,44 @@
|
|
1
|
+
<%- accessor = lambda { |node| node.accessor.tr("?", "") }; order = lambda { |nodes| nodes.sort_by { |n| n.name } } %>
|
2
|
+
<%- @class.requires.each do |mod| -%>
|
3
|
+
require "<%= mod %>"
|
4
|
+
<%- end -%>
|
5
|
+
|
6
|
+
<%= @class.module.map { |mod| "module #{mod}" }.join " " %>
|
7
|
+
|
8
|
+
<%= @class.outter_class.map { |klass| "class #{klass}" }.join "; " %>
|
9
|
+
|
10
|
+
class <%= @class.basename %> <%= "< #{@class.superclass}" if @class.superclass %>
|
11
|
+
<%- if @class.element.children.any? %>
|
12
|
+
# Elements
|
13
|
+
<%- order[@class.element.children].each do |attr| -%>
|
14
|
+
attr_accessor :<%= accessor[attr] %>
|
15
|
+
<%- end -%>
|
16
|
+
<% end %>
|
17
|
+
|
18
|
+
<%- if @class.element.attributes.any? %>
|
19
|
+
# Attributes
|
20
|
+
<%- order[@class.element.attributes].each do |attr| -%>
|
21
|
+
attr_accessor :<%= accessor[attr] %>
|
22
|
+
<%- end -%>
|
23
|
+
<%- end -%>
|
24
|
+
|
25
|
+
<%- nodes = order[@class.element.children + @class.element.attributes] %>
|
26
|
+
def initialize(attributes = nil)
|
27
|
+
attributes ||= {}
|
28
|
+
<% nodes.each do |node| %>
|
29
|
+
<%- if node.respond_to?(:array?) && node.array? -%>
|
30
|
+
@<%= accessor[node] %> = Array(attributes[:<%= accessor[node] %>]).dup unless attributes[:<%= accessor[node] %>].nil? <%# should these always ret an array? %>
|
31
|
+
<%- else -%>
|
32
|
+
@<%= accessor[node] %> = attributes[:<%= accessor[node] %>]
|
33
|
+
<%- end -%>
|
34
|
+
<%- end -%>
|
35
|
+
end
|
36
|
+
|
37
|
+
def inspect
|
38
|
+
sprintf "#<%%s:0x%x <%= nodes.map { |node| "@#{accessor[node]}=%s" }.join(", ") %>>", self.class.name, object_id, <%= nodes.map { |node| "@#{accessor[node]}.inspect" }.join(", ") %>
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
<%= @class.outter_class.map { "end" }.join " " %>
|
43
|
+
|
44
|
+
<%= @class.module.map { "end" }.join " " %>
|
@@ -0,0 +1,26 @@
|
|
1
|
+
def accessor_method(node)
|
2
|
+
if node.array?
|
3
|
+
"has_many"
|
4
|
+
elsif node.type.to_s.include?("::") # Class with namespace?
|
5
|
+
"has_one"
|
6
|
+
else
|
7
|
+
"element"
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
# HappyMapper quirk: we need to return nil if there's no namespace, otherwise the parent element's
|
12
|
+
# namespace will be used in XPath searches
|
13
|
+
def namespace(ns)
|
14
|
+
ns.blank? ? "nil" : %|"#{ns.prefix}"|
|
15
|
+
end
|
16
|
+
|
17
|
+
def type_name(node)
|
18
|
+
case node.type
|
19
|
+
when :boolean
|
20
|
+
"Boolean"
|
21
|
+
when "Object"
|
22
|
+
"String"
|
23
|
+
else
|
24
|
+
node.type
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
UNSUPPORTED_TYPES = [:ID, :IDREF, :boolean, "String", "Object"]
|
2
|
+
|
3
|
+
def unsupported_type?(type)
|
4
|
+
UNSUPPORTED_TYPES.include?(type)
|
5
|
+
end
|
6
|
+
|
7
|
+
def namespace_map(klass)
|
8
|
+
ns = [klass.element].concat(klass.element.children).map { |e| e.namespace }.compact.uniq
|
9
|
+
return unless ns.any?
|
10
|
+
|
11
|
+
map = "xml_namespaces "
|
12
|
+
map << ns.map { |e| sprintf('"%s" => "%s"', e.prefix, e) }.join(", ")
|
13
|
+
end
|
14
|
+
|
15
|
+
def type_name(node)
|
16
|
+
name = unsupported_type?(node.type) ? "" : node.type.dup
|
17
|
+
# May be an attribute node
|
18
|
+
if node.respond_to?(:array?) && node.array?
|
19
|
+
name.prepend "["
|
20
|
+
name.concat "]"
|
21
|
+
end
|
22
|
+
name
|
23
|
+
end
|
24
|
+
|
25
|
+
def accessor_name(node)
|
26
|
+
name = ":#{node.accessor}"
|
27
|
+
name << "?" if node.type == :boolean
|
28
|
+
name
|
29
|
+
end
|
@@ -0,0 +1,213 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
require "jaxb2ruby/type_util"
|
3
|
+
|
4
|
+
describe JAXB2Ruby::Converter do
|
5
|
+
it "creates ruby classes" do
|
6
|
+
classes = convert("address")
|
7
|
+
classes.size.must_equal(2)
|
8
|
+
|
9
|
+
hash = class_hash(classes)
|
10
|
+
hash["Address"].must_be_instance_of(JAXB2Ruby::RubyClass)
|
11
|
+
hash["Address"].name.must_equal("Com::Example::Address")
|
12
|
+
hash["Address"].module.must_equal("Com::Example")
|
13
|
+
hash["Address"].basename.must_equal("Address")
|
14
|
+
hash["Address"].outter_class.must_be_nil
|
15
|
+
hash["Address"].superclass.must_be_nil
|
16
|
+
|
17
|
+
hash["Recipient"].must_be_instance_of(JAXB2Ruby::RubyClass)
|
18
|
+
hash["Recipient"].name.must_equal("Com::Example::Recipient")
|
19
|
+
hash["Recipient"].module.must_equal("Com::Example")
|
20
|
+
hash["Recipient"].basename.must_equal("Recipient")
|
21
|
+
hash["Recipient"].superclass.must_be_nil
|
22
|
+
hash["Recipient"].outter_class.must_be_nil
|
23
|
+
end
|
24
|
+
|
25
|
+
it "creates inner classes from complex anonymous types" do
|
26
|
+
hash = class_hash(convert("types"))
|
27
|
+
hash["NestedClass"].must_be_instance_of(JAXB2Ruby::RubyClass)
|
28
|
+
hash["NestedClass"].name.must_equal("Com::Example::Types::Types::NestedClass")
|
29
|
+
hash["NestedClass"].module.must_equal("Com::Example::Types")
|
30
|
+
hash["NestedClass"].outter_class.must_equal("Types")
|
31
|
+
hash["NestedClass"].basename.must_equal("NestedClass")
|
32
|
+
end
|
33
|
+
|
34
|
+
it "creates superclasses from complex extension bases" do
|
35
|
+
hash = class_hash(convert("types"))
|
36
|
+
hash["TextSubType"].must_be_instance_of(JAXB2Ruby::RubyClass)
|
37
|
+
hash["TextSubType"].name.must_equal("Com::Example::Types::TextSubType")
|
38
|
+
hash["TextSubType"].superclass.must_equal("Com::Example::Types::TextType")
|
39
|
+
end
|
40
|
+
|
41
|
+
it "creates an element for each class" do
|
42
|
+
classes = convert("address")
|
43
|
+
|
44
|
+
hash = class_hash(classes)
|
45
|
+
hash["Address"].element.must_be_instance_of(JAXB2Ruby::Element)
|
46
|
+
hash["Address"].element.name.must_match(/\Ans\d+:Address\z/)
|
47
|
+
hash["Address"].element.local_name.must_equal("Address")
|
48
|
+
hash["Address"].element.namespace.must_equal("http://example.com")
|
49
|
+
|
50
|
+
hash["Recipient"].element.must_be_instance_of(JAXB2Ruby::Element)
|
51
|
+
hash["Recipient"].element.local_name.must_equal("Recipient")
|
52
|
+
hash["Recipient"].element.name.must_match(/\Ans\d+:Recipient\z/)
|
53
|
+
end
|
54
|
+
|
55
|
+
it "creates the right child elements for each class' element" do
|
56
|
+
classes = convert("address")
|
57
|
+
hash = class_hash(classes)
|
58
|
+
|
59
|
+
elements = class_hash(hash["Address"].element.children)
|
60
|
+
elements.size.must_equal(5)
|
61
|
+
%w[House Street Town County Country].each do |name|
|
62
|
+
elements[name].must_be_instance_of(JAXB2Ruby::Element)
|
63
|
+
elements[name].accessor.must_equal(name.underscore)
|
64
|
+
elements[name].type.must_equal("String")
|
65
|
+
end
|
66
|
+
|
67
|
+
elements = class_hash(hash["Recipient"].element.children)
|
68
|
+
elements.size.must_equal(2)
|
69
|
+
%w[FirstName LastName].each do |name|
|
70
|
+
elements[name].must_be_instance_of(JAXB2Ruby::Element)
|
71
|
+
elements[name].accessor.must_equal(name.underscore)
|
72
|
+
elements[name].type.must_equal("String")
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
it "creates the right attributes for each class" do
|
77
|
+
classes = class_hash(convert("address"))
|
78
|
+
classes["Address"].element.attributes.size.must_equal(2)
|
79
|
+
|
80
|
+
hash = class_hash(classes["Address"].element.attributes)
|
81
|
+
attr = hash["PostCode"]
|
82
|
+
attr.name.must_equal("PostCode")
|
83
|
+
attr.local_name.must_equal("PostCode")
|
84
|
+
attr.accessor.must_equal("post_code")
|
85
|
+
attr.type.must_equal("String")
|
86
|
+
|
87
|
+
attr = hash["State"]
|
88
|
+
attr.name.must_equal("State")
|
89
|
+
attr.local_name.must_equal("State")
|
90
|
+
attr.accessor.must_equal("state_code")
|
91
|
+
attr.type.must_equal("String")
|
92
|
+
|
93
|
+
classes["Recipient"].element.attributes.must_be_empty
|
94
|
+
end
|
95
|
+
|
96
|
+
it "detects classes that are a root xml element" do
|
97
|
+
classes = class_hash(convert("types"))
|
98
|
+
classes["Types"].element.root?.must_equal(true)
|
99
|
+
classes["NestedClass"].element.root?.must_equal(false)
|
100
|
+
end
|
101
|
+
|
102
|
+
it "detects types that are nillable" do
|
103
|
+
classes = class_hash(convert("types"))
|
104
|
+
nodes = node_hash(classes["Types"].element)
|
105
|
+
nodes["nillable"].nillable?.must_equal(true)
|
106
|
+
nodes["element"].nillable?.must_equal(false)
|
107
|
+
end
|
108
|
+
|
109
|
+
it "detects classes that are arrays" do
|
110
|
+
classes = class_hash(convert("types"))
|
111
|
+
nodes = node_hash(classes["Types"].element)
|
112
|
+
nodes["idrefs"].array?.must_equal(true)
|
113
|
+
nodes["idrefs"].type.must_equal("Object")
|
114
|
+
|
115
|
+
nodes["anyType"].must_be_instance_of(JAXB2Ruby::Element)
|
116
|
+
nodes["anyType"].array?.must_equal(false)
|
117
|
+
end
|
118
|
+
|
119
|
+
it "detects classes that contain text nodes" do
|
120
|
+
classes = class_hash(convert("types"))
|
121
|
+
classes["Types"].element.text?.must_equal(false)
|
122
|
+
classes["TextType"].element.text?.must_equal(true)
|
123
|
+
end
|
124
|
+
|
125
|
+
it "detects elements that are required" do
|
126
|
+
classes = class_hash(convert("address"))
|
127
|
+
required = node_hash(classes["Recipient"].element).select { |_, v| v.required? }
|
128
|
+
required.size.must_equal(2)
|
129
|
+
required.must_include("FirstName")
|
130
|
+
required.must_include("LastName")
|
131
|
+
|
132
|
+
required = node_hash(classes["Address"].element).select { |_, v| v.required? }
|
133
|
+
required.size.must_equal(4)
|
134
|
+
%w[House Street Town PostCode].each { |attr| required.must_include(attr) }
|
135
|
+
end
|
136
|
+
|
137
|
+
it "detects attributes that are required" do
|
138
|
+
classes = class_hash(convert("address"))
|
139
|
+
required = classes["Recipient"].element.attributes.select { |_, v| v.required? }
|
140
|
+
required.must_be_empty
|
141
|
+
|
142
|
+
required = class_hash(classes["Address"].element.attributes).select { |_, v| v.required? }
|
143
|
+
required.size.must_equal(1)
|
144
|
+
required.first.must_include("PostCode")
|
145
|
+
end
|
146
|
+
|
147
|
+
it "detects element defaults" do
|
148
|
+
classes = class_hash(convert("address"))
|
149
|
+
defaults = class_hash(classes["Recipient"].element.children).reject { |_, v| v.default.nil? }
|
150
|
+
defaults.must_be_empty
|
151
|
+
|
152
|
+
defaults = class_hash(classes["Address"].element.children).reject { |_, v| v.default.nil? }
|
153
|
+
defaults.size.must_equal(1)
|
154
|
+
defaults.must_include("Country")
|
155
|
+
defaults["Country"].default.must_equal("US")
|
156
|
+
end
|
157
|
+
|
158
|
+
it "detects attribute defaults" do
|
159
|
+
skip "No all XJC implementations support attribute defaults... but we do"
|
160
|
+
end
|
161
|
+
|
162
|
+
describe "given a namespace to module mapping" do
|
163
|
+
let(:mod) { "A::Namespace" }
|
164
|
+
let(:nsmap) { { "http://example.com" => mod } }
|
165
|
+
|
166
|
+
it "converts elements in the given namespace to the classes in the given module" do
|
167
|
+
hash = class_hash(convert("address", :namespace => nsmap))
|
168
|
+
hash["Address"].must_be_instance_of(JAXB2Ruby::RubyClass)
|
169
|
+
hash["Address"].name.must_equal("#{mod}::Address")
|
170
|
+
hash["Address"].module.must_equal(mod)
|
171
|
+
hash["Address"].basename.must_equal("Address")
|
172
|
+
end
|
173
|
+
end
|
174
|
+
|
175
|
+
describe "given an XML Schema type to Ruby type mapping" do
|
176
|
+
let(:typemap) { {
|
177
|
+
"anySimpleType" => "My::Type",
|
178
|
+
"boolean" => "TrueClass"
|
179
|
+
} }
|
180
|
+
|
181
|
+
# describe "elements without a mapping" do
|
182
|
+
# it "does not convert them" do
|
183
|
+
# end
|
184
|
+
# end
|
185
|
+
|
186
|
+
describe "elements with a mapping" do
|
187
|
+
it "converts them to the given classes" do
|
188
|
+
classes = class_hash(convert("types", :typemap => typemap))
|
189
|
+
nodes = node_hash(classes["Types"].element)
|
190
|
+
typemap.each do |xsd, ruby|
|
191
|
+
nodes[xsd].must_be_instance_of(JAXB2Ruby::Element)
|
192
|
+
nodes[xsd].type.must_equal(ruby)
|
193
|
+
end
|
194
|
+
end
|
195
|
+
end
|
196
|
+
end
|
197
|
+
|
198
|
+
describe "XML schema to ruby data type mapping" do
|
199
|
+
let(:nodes) {
|
200
|
+
classes = class_hash(convert("types"))
|
201
|
+
node_hash(classes["Types"].element)
|
202
|
+
}
|
203
|
+
|
204
|
+
# TODO: nillablePrimitiveArray
|
205
|
+
JAXB2Ruby::TypeUtil::SCHEMA_TO_RUBY.each do |xsd, ruby|
|
206
|
+
it "maps the schema type #{xsd} to the ruby type #{ruby}" do
|
207
|
+
# xsd type is also the accessor name
|
208
|
+
nodes[xsd].must_be_instance_of(JAXB2Ruby::Element)
|
209
|
+
nodes[xsd].type.must_equal(ruby)
|
210
|
+
end
|
211
|
+
end
|
212
|
+
end
|
213
|
+
end
|