mappum 0.2.0
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 +4 -0
- data/LICENSE +15 -0
- data/README +53 -0
- data/Rakefile +48 -0
- data/VERSION +1 -0
- data/bin/mapserver.rb +4 -0
- data/java-api/pom.xml +63 -0
- data/java-api/src/main/java/pl/ivmx/mappum/JavaTransform.java +12 -0
- data/java-api/src/main/java/pl/ivmx/mappum/MappumApi.java +83 -0
- data/java-api/src/main/java/pl/ivmx/mappum/TreeElement.java +23 -0
- data/java-api/src/main/java/pl/ivmx/mappum/WorkdirLoader.java +12 -0
- data/java-api/src/test/java/iv/Client.java +237 -0
- data/java-api/src/test/java/iv/Person.java +261 -0
- data/java-api/src/test/java/pl/ivmx/mappum/MappumTest.java +122 -0
- data/java-api/src/test/resources/map/example_map.rb +88 -0
- data/lib/mappum.rb +46 -0
- data/lib/mappum/autoconv_catalogue.rb +43 -0
- data/lib/mappum/dsl.rb +255 -0
- data/lib/mappum/java_transform.rb +107 -0
- data/lib/mappum/map.rb +194 -0
- data/lib/mappum/mapserver/mapgraph.rb +192 -0
- data/lib/mappum/mapserver/mapserver.rb +213 -0
- data/lib/mappum/mapserver/maptable.rb +80 -0
- data/lib/mappum/mapserver/views/doc.erb +15 -0
- data/lib/mappum/mapserver/views/main.erb +39 -0
- data/lib/mappum/mapserver/views/maptable.erb +16 -0
- data/lib/mappum/mapserver/views/rubysource.erb +25 -0
- data/lib/mappum/mapserver/views/transform-ws.wsdl.erb +50 -0
- data/lib/mappum/mapserver/views/ws-error.erb +10 -0
- data/lib/mappum/open_xml_object.rb +68 -0
- data/lib/mappum/ruby_transform.rb +199 -0
- data/lib/mappum/xml_transform.rb +382 -0
- data/mappum.gemspec +117 -0
- data/sample/address_fixture.xml +11 -0
- data/sample/crm.rb +9 -0
- data/sample/crm_client.xsd +28 -0
- data/sample/erp.rb +7 -0
- data/sample/erp_person.xsd +44 -0
- data/sample/example_conversions.rb +12 -0
- data/sample/example_map.rb +92 -0
- data/sample/example_notypes.rb +77 -0
- data/sample/example_when.rb +13 -0
- data/sample/person_fixture.xml +23 -0
- data/sample/person_fixture_any.xml +26 -0
- data/sample/server/map/example_any.rb +28 -0
- data/sample/server/map/example_soap4r.rb +59 -0
- data/sample/server/mapserver.sh +1 -0
- data/sample/server/schema/crm_client.xsd +29 -0
- data/sample/server/schema/erp/erp_person.xsd +38 -0
- data/test/test_conversions.rb +24 -0
- data/test/test_example.rb +175 -0
- data/test/test_openstruct.rb +129 -0
- data/test/test_soap4r.rb +108 -0
- data/test/test_when.rb +35 -0
- data/test/test_xml_any.rb +62 -0
- metadata +164 -0
@@ -0,0 +1,80 @@
|
|
1
|
+
module Mappum
|
2
|
+
module MapServer
|
3
|
+
class MapTable
|
4
|
+
attr_reader :edge_maps
|
5
|
+
|
6
|
+
def initialize(map)
|
7
|
+
unless map.normalized?
|
8
|
+
raise "Tables are for unidirectional maps only"
|
9
|
+
end
|
10
|
+
@edge_maps = {}
|
11
|
+
|
12
|
+
@max_llevel, @max_rlevel = 0, 0
|
13
|
+
findMaxLevel(map)
|
14
|
+
@table = "<TABLE BORDER=1 CELLPADDING=3 CELLSPACING=1 RULES=ALL FRAME=BOX>" + getRowsFrom(map).join("\n") + "</TABLE>"
|
15
|
+
end
|
16
|
+
def getHtml()
|
17
|
+
return @table
|
18
|
+
end
|
19
|
+
private
|
20
|
+
def getRowsFrom(map,rlevel=0,llevel=0)
|
21
|
+
|
22
|
+
lname = map.from.name.to_s if map.from.respond_to?(:name)
|
23
|
+
rname = map.to.name.to_s if map.to.respond_to?(:name)
|
24
|
+
|
25
|
+
lname ||= ""
|
26
|
+
rname ||= ""
|
27
|
+
|
28
|
+
lname += "(#{map.from.clazz.to_s})" if map.from.respond_to?(:clazz) and not map.from.clazz.nil?
|
29
|
+
rname += "(#{map.to.clazz.to_s})" if map.to.respond_to?(:clazz) and not map.to.clazz.nil?
|
30
|
+
|
31
|
+
|
32
|
+
llevel = llevel -1 if map.from.respond_to?(:placeholder?) and map.from.placeholder?
|
33
|
+
rlevel = rlevel -1 if map.to.respond_to?(:placeholder?) and map.to.placeholder?
|
34
|
+
|
35
|
+
rows=[]
|
36
|
+
oper = ""
|
37
|
+
map.maps.each do |submap|
|
38
|
+
rows += getRowsFrom(submap,rlevel+1,llevel+1)
|
39
|
+
end
|
40
|
+
|
41
|
+
oper = ">>" if map.maps.empty?
|
42
|
+
oper = ">f>" unless map.func.nil?
|
43
|
+
unless map.dict.nil?
|
44
|
+
@edge_maps[@edge_maps.size+1]=map
|
45
|
+
oper = ">d<font style='vertical-align: super; font-size: smaller;'>#{@edge_maps.size}</font>>"
|
46
|
+
end
|
47
|
+
|
48
|
+
oper = "set constant \"#{map.from.value.to_s}\"" if map.from.kind_of?(Constant)
|
49
|
+
oper = "Func call" if map.from.kind_of?(Function)
|
50
|
+
oper += "<BR/><FONT style='color: #009020;'> #{map.desc} </FONT>" unless map.desc.nil?
|
51
|
+
|
52
|
+
lempy_td = ""
|
53
|
+
llevel.times{lempy_td += "<TD> </TD>"}
|
54
|
+
rempy_td = ""
|
55
|
+
rlevel.times{rempy_td += "<TD> </TD>"}
|
56
|
+
|
57
|
+
lstyle = ""
|
58
|
+
#color structure names
|
59
|
+
lstyle = "bgcolor='#AAAAAA'" if not map.maps.empty? and map.from.respond_to?(:placeholder?) and not map.from.placeholder?
|
60
|
+
rstyle = ""
|
61
|
+
#color structure names
|
62
|
+
rstyle = "bgcolor='#AAAAAA'" if not map.maps.empty? and map.to.respond_to?(:placeholder?) and not map.to.placeholder?
|
63
|
+
|
64
|
+
row = "<TR>#{lempy_td}<TD #{lstyle} colspan='#{@max_llevel +1 - llevel}'>#{lname}</TD>"
|
65
|
+
row += "<TD align='center'>#{oper}</TD>"
|
66
|
+
row += "#{rempy_td}<TD #{rstyle} colspan='#{@max_rlevel+1 - rlevel}'>#{rname}</TD></TR>"
|
67
|
+
|
68
|
+
rows = [row] + rows
|
69
|
+
return rows
|
70
|
+
end
|
71
|
+
def findMaxLevel(map,rlevel=0,llevel=0)
|
72
|
+
map.maps.each do |submap|
|
73
|
+
findMaxLevel(submap,rlevel+1,llevel+1)
|
74
|
+
end
|
75
|
+
@max_llevel = [@max_llevel,llevel].max
|
76
|
+
@max_rlevel = [@max_rlevel,rlevel].max
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
<html>
|
2
|
+
<body>
|
3
|
+
<h1><%=@map_name%></h1>
|
4
|
+
<p>
|
5
|
+
<%=@map.desc%>
|
6
|
+
</p>
|
7
|
+
<object type="image/svg+xml" data="/<%=@catalogue%>/svggraph?map=<%=@map_name%>"><img src="/<%=@catalogue%>/pnggraph?map=<%=@map_name%>"></object>
|
8
|
+
<table border="1" cellspacing="0">
|
9
|
+
<tr><td>Number</td><td>Description</td><td>Technical explanation</td></tr>
|
10
|
+
<%@edge_maps.each do |k, edm, expl|%>
|
11
|
+
<tr><td><%=k%></td><td><%=edm.desc%> </td><td><%=expl%> </td></tr>
|
12
|
+
<%end%>
|
13
|
+
</table>
|
14
|
+
</body>
|
15
|
+
<html>
|
@@ -0,0 +1,39 @@
|
|
1
|
+
<html>
|
2
|
+
<body>
|
3
|
+
<form action="/" method="get">
|
4
|
+
Catalogue:
|
5
|
+
<select name="catalogue">
|
6
|
+
<%@catalogues.each do |cat|%>
|
7
|
+
<option value="<%=cat%>" <%="selected='true'" if cat == @catalogue%>><%=cat%></option>
|
8
|
+
<%end%>
|
9
|
+
</select>
|
10
|
+
<input type="submit" value="Change"/> (<a href="/<%=@catalogue%>/transform-ws.wsdl">wsdl</a>)
|
11
|
+
</form>
|
12
|
+
<form action="/<%=@catalogue%>/transform" method="post">
|
13
|
+
<p>
|
14
|
+
<select name="map">
|
15
|
+
<option value="auto_select" selected="true">auto select</option>
|
16
|
+
<%@maps_name_source.collect do |mn, source|%>
|
17
|
+
<option value='<%=mn%>'><%=mn%></option>
|
18
|
+
<%end%>
|
19
|
+
</select>
|
20
|
+
<input type="checkbox" name="ignore" value="false">Ignore types</input>
|
21
|
+
<br/>
|
22
|
+
<TEXTAREA name="doc" rows="20" cols="80"></TEXTAREA><br/>
|
23
|
+
<INPUT type="submit" value="Send"/><INPUT type="reset"/>
|
24
|
+
</p>
|
25
|
+
</form>
|
26
|
+
<BR/>
|
27
|
+
Bidirectional maps:<p>
|
28
|
+
<%@bidi_maps_name_source.each do |mn, source|%>
|
29
|
+
<a href='/<%=@catalogue%>/doc?map=<%=mn%>'><%=mn%></a> (<a href='<%=source%>'>source</a>)<br/>
|
30
|
+
<%end%>
|
31
|
+
</p>
|
32
|
+
<BR/>
|
33
|
+
Unidirectional maps:<p>
|
34
|
+
<%@maps_name_source.collect do |mn, source|%>
|
35
|
+
<a href='/<%=@catalogue%>/doc?map=<%=mn%>'><%=mn%></a> (<a href='/<%=@catalogue%>/maptable?map=<%=mn%>'>table</a>) (<a href='<%=source%>'>source</a>)<br/>
|
36
|
+
<%end%>
|
37
|
+
</p>
|
38
|
+
</body>
|
39
|
+
<html>
|
@@ -0,0 +1,16 @@
|
|
1
|
+
<html>
|
2
|
+
<body>
|
3
|
+
<h1><%=@map_name%></h1>
|
4
|
+
<p>
|
5
|
+
<%=@map.desc%>
|
6
|
+
</p>
|
7
|
+
<%=@maptable.getHtml%>
|
8
|
+
<h2>Dictionaries:</h2>
|
9
|
+
<table border="1" cellspacing="0">
|
10
|
+
<tr><td>Number</td><td>Description</td><td>Technical explanation</td></tr>
|
11
|
+
<%@edge_maps.each do |k, edm, expl|%>
|
12
|
+
<tr><td><%=k%></td><td><%=edm.desc%> </td><td><%=expl%> </td></tr>
|
13
|
+
<%end%>
|
14
|
+
</table>
|
15
|
+
</body>
|
16
|
+
<html>
|
@@ -0,0 +1,25 @@
|
|
1
|
+
<html>
|
2
|
+
<head>
|
3
|
+
<style type='text/css'>
|
4
|
+
.normal {}
|
5
|
+
.comment { color: #005; font-style: italic; }
|
6
|
+
.keyword { color: #A00; font-weight: bold; }
|
7
|
+
.method { color: #077; }
|
8
|
+
.class { color: #074; }
|
9
|
+
.module { color: #050; }
|
10
|
+
.punct { color: #447; font-weight: bold; }
|
11
|
+
.symbol { color: #099; }
|
12
|
+
.string { color: #944; }
|
13
|
+
.char { color: #F07; }
|
14
|
+
.ident { color: #004; }
|
15
|
+
.constant { color: #07F; }
|
16
|
+
.regex { color: #B66; }
|
17
|
+
.number { color: #D55; }
|
18
|
+
.attribute { color: #377; }
|
19
|
+
.global { color: #3B7; }
|
20
|
+
.expr { color: #227; }
|
21
|
+
</style>
|
22
|
+
</head>
|
23
|
+
<body>
|
24
|
+
<%=@body%>
|
25
|
+
</body>
|
@@ -0,0 +1,50 @@
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
2
|
+
<wsdl:definitions name="transfer-ws"
|
3
|
+
targetNamespace="http://mappum.ivmx.pl/transfer-ws/" xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"
|
4
|
+
xmlns:tns="http://mappum.ivmx.pl/transfer-ws/" xmlns:xsd="http://www.w3.org/2001/XMLSchema"
|
5
|
+
xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
|
6
|
+
<%@xml_imports.each do |file, namespace|%>
|
7
|
+
xmlns:<%=get_xmlns(namespace)%>="<%=namespace%>"
|
8
|
+
<%end%>>
|
9
|
+
|
10
|
+
<%@xml_imports.each do |file, namespace|%>
|
11
|
+
<wsdl:import namespace="<%=namespace%>"
|
12
|
+
location="<%=file%>"/>
|
13
|
+
<%end%>
|
14
|
+
<%@xml_elements.each do |qname|%>
|
15
|
+
<wsdl:message name="<%=qname.name%>">
|
16
|
+
<wsdl:part name="parameters" element="<%=get_xmlns(qname.namespace)%>:<%=qname.name%>"/>
|
17
|
+
</wsdl:message>
|
18
|
+
<%end%>
|
19
|
+
<wsdl:message name="any">
|
20
|
+
<wsdl:part name="parameters" type="xsd:anyType"/>
|
21
|
+
</wsdl:message>
|
22
|
+
<wsdl:portType name="default">
|
23
|
+
<%@xml_maps.each do |name, from, to|%>
|
24
|
+
<wsdl:operation name="<%=name%>">
|
25
|
+
<wsdl:input message="tns:<%=from.name%>"/>
|
26
|
+
<wsdl:output message="tns:<%=to.name%>"/>
|
27
|
+
</wsdl:operation>
|
28
|
+
<%end%>
|
29
|
+
</wsdl:portType>
|
30
|
+
<wsdl:binding name="binding" type="tns:default">
|
31
|
+
<soap:binding style="document"
|
32
|
+
transport="http://schemas.xmlsoap.org/soap/http" />
|
33
|
+
<%@xml_maps.each do |name, from, to|%>
|
34
|
+
<wsdl:operation name="<%=name%>">
|
35
|
+
<soap:operation soapAction="<%=name%>" />
|
36
|
+
<wsdl:input>
|
37
|
+
<soap:body use="literal" />
|
38
|
+
</wsdl:input>
|
39
|
+
<wsdl:output>
|
40
|
+
<soap:body use="literal" />
|
41
|
+
</wsdl:output>
|
42
|
+
</wsdl:operation>
|
43
|
+
<%end%>
|
44
|
+
</wsdl:binding>
|
45
|
+
<wsdl:service name="transfer">
|
46
|
+
<wsdl:port name="http" binding="tns:binding">
|
47
|
+
<soap:address location="http://localhost:9292/transform-ws" />
|
48
|
+
</wsdl:port>
|
49
|
+
</wsdl:service>
|
50
|
+
</wsdl:definitions>
|
@@ -0,0 +1,10 @@
|
|
1
|
+
<env:Envelope xmlns:env="http://schemas.xmlsoap.org/soap/envelope/">
|
2
|
+
<env:Body>
|
3
|
+
<env:Fault>
|
4
|
+
<faultcode><%=ERB::Util.html_escape @error.class.to_s%></faultcode>
|
5
|
+
<faultstring><%=ERB::Util.html_escape @error.message%></faultstring>
|
6
|
+
<faultactor>Server</faultactor>
|
7
|
+
<detail><%=ERB::Util.html_escape @error.backtrace.join("\n")%></detail>
|
8
|
+
</env:Fault>
|
9
|
+
</env:Body>
|
10
|
+
</env:Envelope>
|
@@ -0,0 +1,68 @@
|
|
1
|
+
class SOAP::Mapping::Object
|
2
|
+
def id
|
3
|
+
self[XSD::QName.new(nil, "id")]
|
4
|
+
end
|
5
|
+
def type
|
6
|
+
self[XSD::QName.new(nil, "type")]
|
7
|
+
end
|
8
|
+
|
9
|
+
#
|
10
|
+
# XmlAny element is equal to the other xmlAny element when it
|
11
|
+
# has same elements and attributes regardles of ordering of
|
12
|
+
# elements and attributes.
|
13
|
+
#
|
14
|
+
def == other
|
15
|
+
return false if other.class != self.class
|
16
|
+
return false if @__xmlele - other.__xmlele == []
|
17
|
+
return false if @__xmlattr != other.__xmlattr
|
18
|
+
return true
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
class OpenXmlObject < SOAP::Mapping::Object
|
23
|
+
def method_missing(sym, *args, &block)
|
24
|
+
|
25
|
+
safename = XSD::CodeGen::GenSupport.safemethodname(sym.to_s).to_sym
|
26
|
+
|
27
|
+
if safename != sym and self.respond_to?(safename)
|
28
|
+
return self.send(safename, *args, &block)
|
29
|
+
end
|
30
|
+
|
31
|
+
if sym.to_s[-1..-1] == "=" then
|
32
|
+
if sym.to_s[0..7] == "xmlattr_"
|
33
|
+
#attribute
|
34
|
+
name = sym.to_s[8..-2]
|
35
|
+
__add_xmlattr_from_method(name, args[0])
|
36
|
+
else
|
37
|
+
#element
|
38
|
+
__add_xmlele_from_method(sym.to_s[0..-2], args[0])
|
39
|
+
end
|
40
|
+
else
|
41
|
+
super(sym, *args, &block)
|
42
|
+
end
|
43
|
+
end
|
44
|
+
def id=(value)
|
45
|
+
__add_xmlele_from_method("id", value)
|
46
|
+
end
|
47
|
+
def type=(value)
|
48
|
+
__add_xmlele_from_method("type",value)
|
49
|
+
end
|
50
|
+
private
|
51
|
+
def __add_xmlattr_from_method(name, value)
|
52
|
+
@__xmlattr[XSD::QName.new(nil, name)] = value
|
53
|
+
self.instance_eval <<-EOS
|
54
|
+
def xmlattr_#{name}
|
55
|
+
@__xmlattr[XSD::QName.new(nil, '#{name}')]
|
56
|
+
end
|
57
|
+
|
58
|
+
def xmlattr_#{name}=(value)
|
59
|
+
@__xmlattr[XSD::QName.new(nil, '#{name}')] = value
|
60
|
+
end
|
61
|
+
EOS
|
62
|
+
end
|
63
|
+
def __add_xmlele_from_method(name, value)
|
64
|
+
Thread.current[:SOAPMapping] ||= {}
|
65
|
+
Thread.current[:SOAPMapping][:SafeMethodName] ||= {}
|
66
|
+
__add_xmlele_value(XSD::QName.new(nil, name),value)
|
67
|
+
end
|
68
|
+
end
|
@@ -0,0 +1,199 @@
|
|
1
|
+
# TODO docs
|
2
|
+
require 'set'
|
3
|
+
require 'mappum'
|
4
|
+
require 'ostruct'
|
5
|
+
require 'mappum/autoconv_catalogue'
|
6
|
+
|
7
|
+
module Mappum
|
8
|
+
#
|
9
|
+
# Main class handling transformation of ruby to ruby objects.
|
10
|
+
# This class is a base for other transformations in Mappum.
|
11
|
+
#
|
12
|
+
class RubyTransform
|
13
|
+
attr_accessor :map_catalogue
|
14
|
+
|
15
|
+
def initialize(map_catalogue=nil, default_struct_class=nil, force_open_struct=false)
|
16
|
+
@map_catalogue = map_catalogue if map_catalogue.kind_of?(Mappum::Map)
|
17
|
+
@map_catalogue ||= Mappum.catalogue(map_catalogue)
|
18
|
+
@autoconv_map_catalogue = Mappum.catalogue("MAPPUM_AUTOCONV")
|
19
|
+
@default_struct_class = default_struct_class
|
20
|
+
@force_open_struct = force_open_struct
|
21
|
+
@default_struct_class ||= Mappum::OpenStruct;
|
22
|
+
end
|
23
|
+
#
|
24
|
+
# Method for transforming from object using map to "to" object.
|
25
|
+
#
|
26
|
+
def transform(from, map=nil, to=nil)
|
27
|
+
|
28
|
+
raise RuntimeError.new("Map catalogue is empty!") if @map_catalogue.nil?
|
29
|
+
|
30
|
+
map ||= @map_catalogue[from.class]
|
31
|
+
|
32
|
+
map = @map_catalogue[map] if map.kind_of?(Symbol) or map.kind_of?(String)
|
33
|
+
|
34
|
+
raise MapMissingException.new(from) if map.nil?
|
35
|
+
|
36
|
+
# skip mapping on false :map_when function
|
37
|
+
return to unless map.map_when.nil? or map.map_when.call(from)
|
38
|
+
|
39
|
+
all_nils = true
|
40
|
+
map.maps.each do |sm|
|
41
|
+
from_value, to_value = nil, nil
|
42
|
+
|
43
|
+
if sm.from.respond_to?(:name)
|
44
|
+
from_value = get(from, sm.from.name)
|
45
|
+
else
|
46
|
+
from_value = sm.from.value
|
47
|
+
end
|
48
|
+
|
49
|
+
# skip to next mapping on false :map_when function
|
50
|
+
next unless sm.map_when.nil? or sm.map_when.call(from_value)
|
51
|
+
|
52
|
+
unless sm.func.nil? or (not sm.func_on_nil? and from_value.nil?)
|
53
|
+
from_value = sm.func.call(from_value)
|
54
|
+
end
|
55
|
+
unless sm.from.func.nil? or from_value.nil?
|
56
|
+
mappum_block = sm.from.block
|
57
|
+
if from_value.kind_of?(Array)
|
58
|
+
# TODO Fix it for JavaArrays
|
59
|
+
#or (Module.constants.include? "ArrayJavaProxy" and from_value.kind_of?(Module.const_get(:ArrayJavaProxy)))
|
60
|
+
from_value = from_value.compact.instance_eval(sm.from.func)
|
61
|
+
else
|
62
|
+
from_value = from_value.instance_eval(sm.from.func)
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
submaps = sm.maps
|
67
|
+
if sm.maps.empty?
|
68
|
+
unless sm.submap_alias.nil? or sm.submap_alias.empty?
|
69
|
+
submaps = @map_catalogue[sm.submap_alias].maps
|
70
|
+
end
|
71
|
+
if sm.to.respond_to?(:clazz) and sm.from.respond_to?(:clazz) and sm.from.clazz != sm.to.clazz
|
72
|
+
sub = @map_catalogue[sm.from.clazz,sm.to.clazz]
|
73
|
+
sub ||= @autoconv_map_catalogue[sm.from.clazz,sm.to.clazz]
|
74
|
+
unless sub.nil?
|
75
|
+
submaps = sub.maps
|
76
|
+
else
|
77
|
+
to_value = from_value
|
78
|
+
end
|
79
|
+
else
|
80
|
+
to_value = from_value
|
81
|
+
end
|
82
|
+
end
|
83
|
+
unless submaps.empty? or from_value.nil?
|
84
|
+
if from_value.kind_of?(Array) or
|
85
|
+
(Module.constants.include? "ArrayJavaProxy" and from_value.kind_of?(Module.const_get(:ArrayJavaProxy)))
|
86
|
+
sm_v = sm.clone
|
87
|
+
if sm_v.from.is_array
|
88
|
+
sm_v.from = sm.from.clone
|
89
|
+
sm_v.from.is_array = false
|
90
|
+
end
|
91
|
+
if sm_v.to.is_array
|
92
|
+
sm_v.to = sm.to.clone
|
93
|
+
sm_v.to.is_array = false
|
94
|
+
end
|
95
|
+
sm_v.maps = submaps if sm_v.maps.empty?
|
96
|
+
|
97
|
+
to_value = from_value.collect{|v| transform(v, sm_v)}
|
98
|
+
else
|
99
|
+
to ||= map.to.clazz.new unless @force_open_struct or map.to.clazz.nil? or map.to.clazz.kind_of?(Symbol)
|
100
|
+
to ||= @default_struct_class.new
|
101
|
+
v_to = nil
|
102
|
+
#array values are assigned after return
|
103
|
+
v_to = get(to, sm.to.name) unless sm.to.is_array and not sm.from.is_array
|
104
|
+
sm_v = sm
|
105
|
+
if sm_v.maps.empty?
|
106
|
+
sm_v = sm.clone
|
107
|
+
sm_v.maps = submaps
|
108
|
+
end
|
109
|
+
to_value = transform(from_value, sm_v, v_to)
|
110
|
+
end
|
111
|
+
|
112
|
+
end
|
113
|
+
unless sm.dict.nil?
|
114
|
+
to_value = sm.dict[to_value]
|
115
|
+
end
|
116
|
+
if sm.to.is_array and not sm.from.is_array
|
117
|
+
to_array = convert_from(get(to,sm.to.name),sm.from)
|
118
|
+
to_array ||= []
|
119
|
+
to_array << to_value
|
120
|
+
|
121
|
+
if to_array.empty? and sm.strip_empty?
|
122
|
+
to_array = nil
|
123
|
+
end
|
124
|
+
|
125
|
+
all_nils = false unless to_array.nil?
|
126
|
+
|
127
|
+
if sm.to.name.nil?
|
128
|
+
to = convert_to(to_array, sm.to)
|
129
|
+
else
|
130
|
+
to ||= map.to.clazz.new unless @force_open_struct or map.to.clazz.nil? or map.to.clazz.kind_of?(Symbol)
|
131
|
+
to ||= @default_struct_class.new
|
132
|
+
to.send("#{sm.to.name}=", convert_to(to_array, sm.to)) unless to_array.nil?
|
133
|
+
end
|
134
|
+
else
|
135
|
+
|
136
|
+
if to_value.respond_to?(:empty?) and to_value.empty? and sm.strip_empty?
|
137
|
+
to_value = nil
|
138
|
+
end
|
139
|
+
|
140
|
+
all_nils = false unless to_value.nil?
|
141
|
+
|
142
|
+
if sm.to.name.nil?
|
143
|
+
to ||= to_value
|
144
|
+
else
|
145
|
+
to ||= map.to.clazz.new unless @force_open_struct or map.to.clazz.nil? or map.to.clazz.kind_of?(Symbol)
|
146
|
+
to ||= @default_struct_class.new
|
147
|
+
to.send("#{sm.to.name}=", convert_to(to_value, sm.to)) unless to_value.nil?
|
148
|
+
end
|
149
|
+
end
|
150
|
+
|
151
|
+
end
|
152
|
+
if all_nils and map.strip_empty?
|
153
|
+
return nil
|
154
|
+
end
|
155
|
+
return to
|
156
|
+
end
|
157
|
+
|
158
|
+
protected
|
159
|
+
|
160
|
+
def get(object, field)
|
161
|
+
if field.nil? or object.nil?
|
162
|
+
return object
|
163
|
+
elsif
|
164
|
+
begin
|
165
|
+
return object.send(field)
|
166
|
+
rescue NoMethodError => e
|
167
|
+
#for open structures field will be defined later
|
168
|
+
if object.kind_of?(@default_struct_class)
|
169
|
+
return nil
|
170
|
+
else
|
171
|
+
raise e
|
172
|
+
end
|
173
|
+
end
|
174
|
+
end
|
175
|
+
end
|
176
|
+
def convert_to(to, field_def)
|
177
|
+
return to
|
178
|
+
end
|
179
|
+
def convert_from(from, field_def)
|
180
|
+
return from
|
181
|
+
end
|
182
|
+
end
|
183
|
+
class OpenStruct < OpenStruct
|
184
|
+
def type(*attr)
|
185
|
+
method_missing(:type, *attr)
|
186
|
+
end
|
187
|
+
def id(*attr)
|
188
|
+
method_missing(:id, *attr)
|
189
|
+
end
|
190
|
+
end
|
191
|
+
class MapMissingException < RuntimeError
|
192
|
+
attr_accessor :from
|
193
|
+
def initialize(from, msg=nil)
|
194
|
+
msg ||= "Map for class \"#{from.class}\" not found!"
|
195
|
+
super(msg)
|
196
|
+
@from = from
|
197
|
+
end
|
198
|
+
end
|
199
|
+
end
|