simcha-mappum 0.1.0

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