jaxb2ruby 0.0.1-java
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/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
|