simcha-mappum 0.1.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.
@@ -0,0 +1,4 @@
1
+ nbproject/
2
+ pkg/
3
+ .project
4
+ .buildpath
data/LICENSE ADDED
@@ -0,0 +1,15 @@
1
+ == mappum
2
+
3
+ Copyright 2009 by Jan Topinski
4
+
5
+ Licensed under the Apache License, Version 2.0 (the "License");
6
+ you may not use this file except in compliance with the License.
7
+ You may obtain a copy of the License at
8
+
9
+ http://www.apache.org/licenses/LICENSE-2.0
10
+
11
+ Unless required by applicable law or agreed to in writing, software
12
+ distributed under the License is distributed on an "AS IS" BASIS,
13
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ See the License for the specific language governing permissions and
15
+ limitations under the License.
data/README ADDED
@@ -0,0 +1,53 @@
1
+ == mappum
2
+
3
+ Mappum is the tree to tree (object, bean etc.) mapping DSL. The example of usage
4
+ is provided below. More documentation will follow.
5
+
6
+ Mappum.catalogue_add "CRM-ERP" do
7
+
8
+ map ERP::Person, CRM::Client do |p, c|
9
+
10
+ #simple mapping
11
+ map p.title <=> c.title
12
+
13
+ #map with simple function call
14
+ map p.person_id << c.key.downcase
15
+ map p.person_id.upcase >> c.key
16
+
17
+ #dictionary use
18
+ map p.sex <=> c.sex_id, :dict => {"F" => "1", "M" => "2"}
19
+
20
+ #submaps
21
+ map p.address(ERP::Address) <=> c.address(CRM::Address) do |a, b|
22
+ map a.street <=> b.street
23
+ #etc.
24
+ end
25
+
26
+ #subobject to fields
27
+ map p.main_phone(ERP::Phone) <=> c.self do |a, b|
28
+ map a.number <=> b.main_phone
29
+ map a.type <=> b.main_phone_type
30
+ end
31
+
32
+ #compilcated function call
33
+ map p.name >> c.surname do |name|
34
+ name + "ski"
35
+ end
36
+ map p.name << c.surname do |name|
37
+ if name =~ /ski/
38
+ name[0..-4]
39
+ else
40
+ name
41
+ end
42
+ end
43
+ #field to array and array to field
44
+ map p.email1 <=> c.emails[0]
45
+ map p.email2 <=> c.emails[1]
46
+ map p.email3 <=> c.emails[2]
47
+
48
+ map p.phones(ERP::Phone)[] <=> c.phones[] do |a, b|
49
+ map a.number <=> b.self
50
+ end
51
+
52
+ end
53
+ end
@@ -0,0 +1,46 @@
1
+ #
2
+ # To change this template, choose Tools | Templates
3
+ # and open the template in the editor.
4
+
5
+ require 'rubygems'
6
+ require 'rake'
7
+ require 'rake/clean'
8
+ require 'rake/rdoctask'
9
+ require 'rake/testtask'
10
+ require 'spec/rake/spectask'
11
+
12
+ Rake::RDocTask.new do |rdoc|
13
+ files =['README', 'LICENSE', 'lib/**/*.rb']
14
+ rdoc.rdoc_files.add(files)
15
+ rdoc.main = "README" # page to start on
16
+ rdoc.title = "rupper Docs"
17
+ rdoc.rdoc_dir = 'doc/rdoc' # rdoc output folder
18
+ rdoc.options << '--line-numbers'
19
+ end
20
+
21
+ Rake::TestTask.new do |t|
22
+ t.test_files = FileList['test/**/*.rb']
23
+ end
24
+
25
+ Spec::Rake::SpecTask.new do |t|
26
+ t.spec_files = FileList['spec/**/*.rb']
27
+ end
28
+
29
+ begin
30
+ require 'jeweler'
31
+ Jeweler::Tasks.new do |gemspec|
32
+ gemspec.name = "mappum"
33
+ gemspec.summary = "Mappum is the tree to tree (object, bean etc.) mapping DSL."
34
+ gemspec.email = "jtopinski@chatka.org"
35
+ gemspec.homepage = "http://wiki.github.com/simcha/mappum"
36
+ gemspec.description = ""
37
+ gemspec.authors = ["Jan Topiński"]
38
+ gemspec.add_dependency('facets', '>= 2.5.2')
39
+ gemspec.add_dependency('soap4r', '>= 1.5.8')
40
+ gemspec.add_dependency('sinatra', '>= 0.9.2')
41
+ gemspec.add_dependency('thin', '>= 1.2.2')
42
+ end
43
+ rescue LoadError
44
+ puts "Jeweler not available. Install it with: sudo gem install technicalpickles-jeweler -s http://gems.github.com"
45
+ end
46
+
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.1.0
@@ -0,0 +1,4 @@
1
+ #!/usr/bin/ruby1.8
2
+ $:.unshift File.join(File.dirname(__FILE__),'..','lib')
3
+
4
+ load 'mappum/mapserver/mapserver.rb'
@@ -0,0 +1,19 @@
1
+ # TODO docs
2
+ require 'set'
3
+ require 'mappum/dsl'
4
+ require 'mappum/map'
5
+
6
+ module Mappum
7
+ def self.catalogue_add(name = "ROOT", &block)
8
+ @catalogue ||= {}
9
+ @catalogue[name] ||= RootMap.new(name)
10
+ definition = DSL::RootMap.new(name).make_definition(&block)
11
+ @catalogue[name].maps += definition.maps
12
+ @catalogue[name].bidi_maps += definition.bidi_maps
13
+
14
+ end
15
+ def self.catalogue(name = "ROOT")
16
+ name = "ROOT" if name.nil?
17
+ @catalogue[name]
18
+ end
19
+ end
@@ -0,0 +1,186 @@
1
+ class Object
2
+ def >> field
3
+ return {Mappum::DSL::Constant.new(self) => field} if field.kind_of?(Mappum::DSL::Field)
4
+ throw "Constant can be mapped to field only"
5
+ end
6
+ end
7
+ module Mappum
8
+ module DSL
9
+ class Map
10
+ attr_accessor :def
11
+ def initialize
12
+ @def = Mappum::Map.new
13
+ end
14
+ def map(*attr, &block)
15
+ mapa = FieldMap.new(attr)
16
+
17
+ mapa.def.desc = @comment
18
+ @comment = nil
19
+
20
+ if (not mapa.def.normalized?) && block_given?
21
+ eval_right = mapa.mpun_right.clone
22
+ eval_right.mpun_definition.is_root = true
23
+ eval_left = mapa.mpun_left.clone
24
+ eval_left.mpun_definition.is_root = true
25
+ mapa.instance_exec(eval_left, eval_right, &block)
26
+ elsif block_given?
27
+ mapa.def.func = block
28
+ mapa.def.func_on_nil = true if mapa.mpun_left.kind_of?(Function)
29
+ end
30
+ @def.maps += mapa.def.normalize
31
+ @def.bidi_maps << mapa.def
32
+ return mapa.def
33
+ end
34
+ def `(str)
35
+ @comment ||= ""
36
+ @comment += str
37
+ end
38
+
39
+ def func
40
+ Mappum::DSL::Function.new
41
+ end
42
+ def tree(clazz)
43
+ return Field.new(nil, nil, clazz)
44
+ end
45
+ end
46
+ class RootMap < Map
47
+ def initialize(name)
48
+ @def = Mappum::RootMap.new(name)
49
+ end
50
+ def make_definition &block
51
+ instance_eval(&block)
52
+ @def
53
+ end
54
+ end
55
+ class FieldMap < Map
56
+ attr_accessor :mpun_left, :mpun_right
57
+ def mpun_left=(left_map_dsl)
58
+ @mpun_left=left_map_dsl
59
+ @def.left=left_map_dsl.mpun_definition
60
+ end
61
+ def mpun_right=(right_map_dsl)
62
+ @mpun_right=right_map_dsl
63
+ @def.right=right_map_dsl.mpun_definition
64
+ end
65
+ def initialize(*attr)
66
+ @def = Mappum::FieldMap.new
67
+ type_size = 1
68
+ if attr == [[nil]]
69
+ raise """Can't make map for [[nil]] arguments.
70
+ Can be that You define top level class mapping with \"<=>\" please use \",\" instead (we know its a Bug). """
71
+ end
72
+ mapped = attr[0][0]
73
+ if attr[0][0].instance_of?(Class) or attr[0][0].instance_of?(Symbol) and
74
+ attr[0][1].instance_of?(Class) or attr[0][1].instance_of?(Symbol)
75
+ mapped = [attr[0][0], attr[0][1]]
76
+ type_size = 2
77
+ end
78
+
79
+ if mapped.instance_of?(Array) then
80
+ if(mapped[0]).instance_of?(Class) or (mapped[0]).instance_of?(Symbol)
81
+ @def.strip_empty = false
82
+ self.mpun_left = Field.new(nil,nil,mapped[0])
83
+ else
84
+ self.mpun_left = mapped[0]
85
+ end
86
+ if(mapped[1]).instance_of?(Class) or (mapped[1]).instance_of?(Symbol)
87
+ @def.strip_empty = false
88
+ self.mpun_right = Field.new(nil,nil,mapped[1])
89
+ else
90
+ self.mpun_right = mapped[1]
91
+ end
92
+ end
93
+ if mapped.instance_of?(Hash) then
94
+ self.mpun_left = mapped.keys[0]
95
+ self.mpun_right = mapped.values[0]
96
+ end
97
+
98
+ if mapped.instance_of?(Hash) then
99
+ @def.from = @def.left
100
+ @def.to = @def.right
101
+ end
102
+
103
+ @def.dict = attr[0][1][:dict] if attr[0].size > type_size
104
+ @def.desc = attr[0][1][:desc] if attr[0].size > type_size
105
+
106
+ end
107
+ end
108
+ #Base class for all mapped elements eg. fields, constants
109
+ class Mappet
110
+ def mpun_definition
111
+ @def
112
+ end
113
+ def <=> field
114
+ [self, field]
115
+ end
116
+
117
+ def << field
118
+ return {field => self} if field.kind_of?(Mappum::DSL::Mappet)
119
+ return {Constant.new(field) => self}
120
+ end
121
+
122
+ def >> field
123
+ return {self => field} if field.kind_of?(Mappum::DSL::Mappet)
124
+ throw "Must map to a field"
125
+ end
126
+ end
127
+ class Constant < Mappet
128
+ def initialize(value)
129
+ @def = Mappum::Constant.new
130
+ @def.value = value
131
+ end
132
+ end
133
+
134
+ class Function < Mappet
135
+ def initialize
136
+ @def = Mappum::Function.new
137
+ end
138
+ end
139
+
140
+ class Field < Mappet
141
+ def initialize(parent, name, clazz)
142
+ @def = Mappum::Field.new
143
+ @def.parent = parent
144
+ @def.name = name
145
+ @def.clazz = clazz
146
+ @def.is_array = false
147
+ @def.is_root = false
148
+ end
149
+
150
+ def type(*attr)
151
+ method_missing(:type, *attr)
152
+ end
153
+ def id(*attr)
154
+ method_missing(:id, *attr)
155
+ end
156
+
157
+ def method_missing(symbol, *args)
158
+ if @def.is_root
159
+ if(symbol == :self)
160
+ return Field.new(@def, nil, args[0])
161
+ end
162
+ return Field.new(@def, symbol, args[0])
163
+ end
164
+
165
+ if symbol == :[]
166
+ #empty [] is just indication that field is an array not function
167
+ if args.size == 0
168
+ @def.is_array = true
169
+ return self
170
+ end
171
+ #[n] indicates both mapping function and array
172
+ if args.size == 1 and args[0].instance_of?(Fixnum)
173
+ @def.is_array = true
174
+ end
175
+ end
176
+ if @def.func.nil?
177
+ @def.func = "self.#{symbol}(#{args.join(", ")})"
178
+ else
179
+ @def.func += ".#{symbol}(#{args.join(", ")})"
180
+ end
181
+
182
+ return self
183
+ end
184
+ end
185
+ end
186
+ end
@@ -0,0 +1,133 @@
1
+ module Mappum
2
+ # Base Map class representing mapping betwean two or more types, properties etc.
3
+ class Map
4
+
5
+ attr_accessor :maps, :bidi_maps, :strip_empty
6
+
7
+ def initialize
8
+ @maps = []
9
+ @bidi_maps = []
10
+ @strip_empty = true
11
+ end
12
+ # When value of mapped property is null remove property.
13
+ def strip_empty?
14
+ @strip_empty
15
+ end
16
+ end
17
+
18
+
19
+ class RootMap < Map
20
+ attr_accessor :name
21
+ def initialize(name)
22
+ super()
23
+ @name = name
24
+ @strip_empty = false
25
+ end
26
+ def [](clazz)
27
+ #TODO optimize
28
+ mpa = @maps.find{|m| m.from.clazz == clazz or m.from.clazz.to_s == clazz.to_s }
29
+ return mpa unless mpa.nil?
30
+ return @maps.find{|m| "#{m.from.clazz}-to-#{m.to.clazz}" == clazz.to_s}
31
+ end
32
+ def get_bidi_map(name)
33
+ #TODO optimize
34
+ mpa = @bidi_maps.find{|m| m.right.clazz == name or m.right.clazz.to_s == name.to_s }
35
+ mpa ||= @bidi_maps.find{|m| m.left.clazz == name or m.left.clazz.to_s == name.to_s }
36
+ return mpa unless mpa.nil?
37
+
38
+ return @bidi_maps.find{|m| "#{m.left.clazz}-to-from-#{m.right.clazz}" == name.to_s}
39
+ end
40
+ def list_map_names(full_list = false)
41
+ list = []
42
+ list += @maps.collect{|m| "#{m.from.clazz}-to-#{m.to.clazz}"}
43
+ list += @maps.collect{|m|m.from.clazz} if full_list
44
+ return list
45
+ end
46
+ def list_bidi_map_names
47
+ list = []
48
+ list += @bidi_maps.collect{|m| "#{m.left.clazz}-to-from-#{m.right.clazz}"}
49
+ return list
50
+ end
51
+ end
52
+
53
+ class FieldMap < Map
54
+ attr_accessor :dict, :desc, :left, :right, :func, :to, :from, :func_on_nil
55
+ # True if map is unidirectional. Map is unidirectional
56
+ # when maps one way only.
57
+ def normalized?
58
+ not @from.nil?
59
+ end
60
+
61
+ def normalize
62
+ #if bidirectional
63
+ if not normalized?
64
+ map_l = self.clone
65
+ map_l.to = self.left
66
+ map_l.from = self.right
67
+ map_l.maps = self.maps.select do |m|
68
+ m.to.parent == map_l.to
69
+ end
70
+
71
+ map_l.dict = self.dict.invert unless self.dict.nil?
72
+
73
+ map_r = self.clone
74
+ map_r.to = self.right
75
+ map_r.from = self.left
76
+ map_r.maps = self.maps.select do |m|
77
+ m.to.parent == map_r.to
78
+ end
79
+
80
+ [map_l, map_r]
81
+ else
82
+ [self]
83
+ end
84
+ end
85
+ def simple?
86
+ @func.nil? && @dict.nil? && @desc.nil? &&
87
+ @maps.empty? && @bidi_maps.empty? && @right.func.nil? && @left.func.nil?
88
+ end
89
+ def func_on_nil?
90
+ @func_on_nil
91
+ end
92
+ end
93
+ class Tree
94
+ attr_accessor :parent
95
+
96
+ def initialize(parent)
97
+ @parent = parent
98
+ end
99
+ def method_missing(symbol, *args)
100
+ return Field.new(@parent, symbol, args[0])
101
+ end
102
+ end
103
+ class Field < Struct.new(:name, :clazz, :parent, :func, :is_root, :is_array)
104
+ def array?
105
+ @is_array
106
+ end
107
+ end
108
+ class Constant < Struct.new(:value)
109
+ def parent
110
+ nil
111
+ end
112
+ def is_array
113
+ @value.kind_of?(Array)
114
+ end
115
+ def func
116
+ nil
117
+ end
118
+ end
119
+ class Function
120
+ def parent
121
+ nil
122
+ end
123
+ def array?
124
+ false
125
+ end
126
+ def func
127
+ nil
128
+ end
129
+ def value
130
+ nil
131
+ end
132
+ end
133
+ end