kwatable 0.0.1 → 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (40) hide show
  1. data/ChangeLog.txt +28 -2
  2. data/README.txt +1 -1
  3. data/bin/kwatable +2 -2
  4. data/examples/ex1/Makefile +1 -1
  5. data/examples/ex1/example1.yaml +18 -7
  6. data/examples/ex2/Makefile +1 -1
  7. data/kwatable.gemspec +2 -2
  8. data/lib/kwatable/error-msg.rb +15 -14
  9. data/lib/kwatable/kwatable.schema.yaml +34 -81
  10. data/lib/kwatable/main-program.rb +49 -41
  11. data/lib/kwatable/manipulator.rb +222 -0
  12. data/lib/kwatable/templates/ddl-mysql.eruby +15 -12
  13. data/lib/kwatable/templates/ddl-postgresql.eruby +14 -10
  14. data/lib/kwatable/templates/defaults.yaml +4 -4
  15. data/lib/kwatable/templates/dto-java.eruby +49 -59
  16. data/lib/kwatable/templates/dto-ruby.eruby +47 -54
  17. data/lib/kwatable.rb +3 -4
  18. data/test/assert-diff.rb +1 -1
  19. data/test/test.rb +24 -17
  20. data/test/test1/test1.ddl-mysql.expected +3 -2
  21. data/test/test1/test1.ddl-postgresql.expected +2 -1
  22. data/test/test1/test1.dto-java.Group.expected +12 -9
  23. data/test/test1/test1.dto-java.User.expected +12 -14
  24. data/test/test1/test1.dto-ruby.Group.expected +9 -10
  25. data/test/test1/test1.dto-ruby.User.expected +12 -15
  26. data/test/test1/test1.yaml +18 -7
  27. data/test/test2/test2.ddl-mysql.expected +4 -4
  28. data/test/test2/test2.dto-java.Address.expected +6 -8
  29. data/test/test2/test2.dto-java.Customer.expected +6 -8
  30. data/test/test2/test2.dto-java.Item.expected +5 -7
  31. data/test/test2/test2.dto-java.SalesOrder.expected +6 -8
  32. data/test/test2/test2.dto-java.SalesOrderLine.expected +6 -8
  33. data/test/test2/test2.dto-ruby.Address.expected +6 -9
  34. data/test/test2/test2.dto-ruby.Customer.expected +6 -9
  35. data/test/test2/test2.dto-ruby.Item.expected +5 -8
  36. data/test/test2/test2.dto-ruby.SalesOrder.expected +6 -9
  37. data/test/test2/test2.dto-ruby.SalesOrderLine.expected +6 -9
  38. data/test/test2/test2.yaml +3 -3
  39. metadata +65 -64
  40. data/lib/kwatable/manufactory.rb +0 -213
@@ -0,0 +1,222 @@
1
+ ###
2
+ ### copyright(c) 2005 kuwata-lab.com all rights reserved.
3
+ ### $Release: 0.1.0 $
4
+ ### $Rev: 15 $
5
+ ###
6
+
7
+ require 'yaml'
8
+
9
+ module Kwatable
10
+
11
+ class ManipulationError < KwatableError
12
+ end
13
+
14
+
15
+ ##
16
+ ## ex.
17
+ ## tabledef = YAML.load_file('tabledef.yaml')
18
+ ## manipulator = Kwatable::Manipulator.new
19
+ ## tabledef = manipulator.manipulate(tabledef)
20
+ ## p tabledef[:columns]
21
+ ## p tabledef[:tables]
22
+ ##
23
+ class Manipulator
24
+
25
+ #def parse(input)
26
+ # str = ''
27
+ # input.each_line do |line|
28
+ # str << line.gsub(/([^\t]{8})|([^\t]*)\t/n){[$+].pack("A8")} ## expand tab
29
+ # end
30
+ # tabledef = YAML.load(str)
31
+ # manipulate(tabledef)
32
+ # return tabledef
33
+ #end
34
+
35
+ def manipulate(tabledef)
36
+ #assert unless tabledef.is_a?(Hash)
37
+ return tabledef unless tabledef.is_a?(Hash)
38
+
39
+ column_map, patterned_columns = _manipulate_columns(tabledef['columns'])
40
+ #assert unless column_map.is_a?(Hash)
41
+ #assert unless patterned_columns.is_a?(Array)
42
+
43
+ table_map = _manipulate_tables(tabledef['tables'], column_map, patterned_columns)
44
+ #assert unless table_map.is_a?(Hash)
45
+
46
+ tabledef['column_map'] = column_map # Hash
47
+ tabledef['table_map'] = table_map # Hash
48
+ return tabledef
49
+ end
50
+
51
+ private
52
+
53
+ def _error(message_key, *args)
54
+ msg = Kwatable.msg(:regexp_invalid) % args
55
+ return ManipulationError.new(msg)
56
+ end
57
+
58
+ def _manipulate_columns(columns)
59
+ column_map = {}
60
+ patterned_columns = []
61
+ columns.each_with_index do |column, i|
62
+ name = column['name']
63
+ unless name
64
+ #* key=:colname_required msg="table '%s': column name required (index=%d)."
65
+ raise _error(:colname_required, table['name'], i)
66
+ end
67
+ if name =~ /\A\/(.*)\/\z/
68
+ pattern = $1
69
+ begin
70
+ namepattern = Regexp.compile(pattern)
71
+ rescue RegexpError => ex
72
+ #* key=:regexp_invalid msg="table '%s': column '%s': pattern %s: %s"
73
+ raise _error(:regexp_invalid, table['name'], column['name'], column['pattern'], ex.message)
74
+ end
75
+ column['namepattern'] = namepattern
76
+ patterned_columns << column
77
+ else
78
+ if column_map.key?(name)
79
+ #* key=:coldef_duplicated msg="table '%s': column '%s': column name is duplicated."
80
+ raise _error(:coldef_duplicated, table['name'], column['name'])
81
+ end
82
+ column_map[name] = column
83
+ end
84
+ #name = column['name'].strip
85
+ #namepattern = column['namepattern']
86
+ #unless name || namepattern
87
+ # #* key=:colname_required msg="column definition doesn't have a name nor namepattern."
88
+ # raise ManipulationError.new(Kwatable.msg(:colname_required))
89
+ #end
90
+ #if name
91
+ # if column_map.key?(name)
92
+ # #* key=:coldef_duplicated msg="column definition `%s' is duplicated."
93
+ # raise ManipulationError.new(Kwatable.msg(:coldef_duplicated) % [name])
94
+ # end
95
+ # column_map[name] = column
96
+ #end
97
+ #if namepattern
98
+ # pattern = namepattern.strip
99
+ # pattern = $1 if pattern =~ /^\/(.*)\/$/
100
+ # column['namepattern'] = Regexp.compile(pattern)
101
+ # patterned_columns << column
102
+ #end
103
+ end if columns
104
+ return column_map, patterned_columns
105
+ end
106
+
107
+ def _manipulate_tables(tables, column_map, patterned_columns)
108
+ #assert unless tables.is_a?(Array)
109
+ #assert unless column_map.is_a?(Hash)
110
+ #assert unless patterned_columns.is_a?(Array)
111
+
112
+ ## create table_map
113
+ table_map = {}
114
+ tables.each_with_index do |table, i|
115
+ name = table['name']
116
+ unless name
117
+ #* key=:tablename_required msg="table definition doesn't have a name (index=%d)."
118
+ raise _error(:tablename_required, i)
119
+ end
120
+ if table_map.key?(name)
121
+ #* key=:tabledef_duplicated msg="table '%s': table name is duplicated."
122
+ raise _error(:tabledef_duplicated, name)
123
+ end
124
+ table_map[name] = table
125
+ end
126
+
127
+ ## manipulate table columns
128
+ tables.each do |table|
129
+ colname_map = {}
130
+ table['columns'].each_with_index do |column, i|
131
+ column['table'] = table
132
+ colname = column['name']
133
+ unless colname
134
+ #* key=:tablecolumn_required msg="table '%s': column name requried (index=%d)."
135
+ raise _error(:tablecolumn_required, table['name'], i)
136
+ end
137
+ if colname_map[colname]
138
+ #* key=:tablecolumn_duplicated msg="table '%s': column '%s': column name is duplicated."
139
+ raise _error(:tablecolumn_duplicated, table['name'], colname)
140
+ end
141
+ colname_map[colname] = true
142
+ _set_defaults(column, column_map, patterned_columns)
143
+ #_alias_keys(column, "primary-key", "primarykey", "identifier")
144
+ #_alias_keys(column, "not-null", "notnull", "required")
145
+ _alias_key(column, table, "ident", "primary-key")
146
+ _alias_key(column, table, "required", "not-null")
147
+ _handle_ref(column, table, table_map) if column['ref']
148
+ _handle_enum(column) if column['enum']
149
+ unless column['type']
150
+ #* key=:tabletype_required msg="table `%s': column `%s': type is not determined."
151
+ raise _error(:tabletype_required, table['name'], column['name'])
152
+ end
153
+ end if table['columns']
154
+ end if tables
155
+
156
+ return table_map
157
+ end
158
+
159
+ def _set_defaults(column, column_map, patterned_columns)
160
+ colname = column['name']
161
+ defaults = column_map[colname]
162
+ defaults ||= patterned_columns.find { |col| colname =~ col['namepattern'] }
163
+ defaults.each do |key, val|
164
+ column[key] = val if !column.key?(key) && key != 'namepattern'
165
+ end if defaults
166
+ end
167
+
168
+ def _alias_keys(column, key, *old_keys) # not used
169
+ old_keys.each do |old_key|
170
+ column[key] = column[old_key] if !column.key?(key) && column.key?(old_key)
171
+ end if old_keys
172
+ end
173
+
174
+ def _alias_key(column, table, key1, key2)
175
+ if column.key?(key1) && column.key?(key2)
176
+ #* key=:alias_conflict msg="table '%s', column '%s': alias key '%1:' and '%2:' are not allowed to use in the same time."
177
+ raise _error(:alias_conflict, table['name'], column['name'], key1, key2)
178
+ end
179
+ column[key2] = column[key1] if column.key?(key1)
180
+ column[key1] = column[key2] if column.key?(key2)
181
+ end
182
+
183
+ def _handle_enum(column)
184
+ return unless column['enum']
185
+ width = 0
186
+ column['enum'].each do |value|
187
+ len = value.to_s.length
188
+ width = len if len > width
189
+ end
190
+ column['type'] ||= 'str'
191
+ column['width'] ||= width
192
+ end
193
+
194
+ def _handle_ref(column, table, table_map)
195
+ ref = column['ref']
196
+ return unless ref
197
+ ref = ref.strip
198
+ return unless ref =~ /\A(\w+)\.(\w+)\z/ || ref =~ /\A(\w+)\((\w+)\)\z/
199
+ ref_table_name = $1
200
+ ref_column_name = $2
201
+ ref_table = table_map[ref_table_name]
202
+ unless ref_table
203
+ #* key=:reftable_notfound msg="`table '%s': column '%s': 'ref: %s': reference table not found."
204
+ raise _error(:reftable_notfound, table['name'], column['name'], column['ref'])
205
+ end
206
+ cols = ref_table['columns']
207
+ ref_column = cols ? cols.find { |col| col['name'] == ref_column_name } : nil
208
+ unless ref_column
209
+ #* key=:refcolumn_notfound msg="`table '%s': column '%s': ref: %s': reference column not found in the table."
210
+ raise _error(:refcolumn_notfound, table['name'], column['name'], column['ref'])
211
+ end
212
+ #column['ref-table'] = ref_table
213
+ #column['ref-column'] = ref_column
214
+ column['ref'] = ref_column
215
+ column['ref-name'] ||= column['name'].sub(/_#{ref_column['name']}$/, '')
216
+ column['type'] = ref_column['type']
217
+ column['width'] ||= ref_column['width'] if ref_column.key?('width')
218
+ end
219
+
220
+ end
221
+
222
+ end
@@ -4,11 +4,12 @@
4
4
  ## kwatable template file for MySQL
5
5
  ##
6
6
  ## copyright(c) 2005 kuwata-lab.com all rights reserved.
7
- ## $Release: 0.0.1 $
8
- ## $Rev: 12 $
7
+ ## $Release: 0.1.0 $
8
+ ## $Rev: 15 $
9
9
  ##
10
10
  ## template properties:
11
11
  ## (none)
12
+ ##
12
13
 
13
14
 
14
15
  #
@@ -62,15 +63,15 @@
62
63
  year_month
63
64
  zerofill
64
65
  END
65
- KEYWORDS = {}
66
- keywords.split(/\s+/).each { |word| KEYWORDS[word] = true }
66
+ @keywords = {}
67
+ keywords.split(/\s+/).each { |word| @keywords[word] = true }
67
68
 
68
69
 
69
70
  #
70
71
  # escape keyword
71
72
  #
72
- def _(word)
73
- return KEYWORDS[word.downcase] ? "`#{word}`" : word
73
+ def self._(word)
74
+ return @keywords[word.downcase] ? "`#{word}`" : word
74
75
  end
75
76
 
76
77
 
@@ -127,10 +128,10 @@ create table <%= _(table['name']) %> (
127
128
  type += "(#{width})" if width
128
129
 
129
130
  #
130
- # set type with 'enum(...)' if column has values
131
+ # set type with 'enum(...)' if column has enum
131
132
  #
132
- if column['values']
133
- type = "enum(" + column['values'].collect{|v| "'#{v}'"}.join(", ") + ")"
133
+ if column['enum']
134
+ type = "enum(" + column['enum'].collect{|v| "'#{v}'"}.join(", ") + ")"
134
135
  width = nil
135
136
  end
136
137
 
@@ -139,8 +140,8 @@ create table <%= _(table['name']) %> (
139
140
  #
140
141
  constraints = []
141
142
  constraints << 'auto_increment' if column['serial']
142
- constraints << 'not null' if column['not-null'] && !column['serial'] && !column['primary-key']
143
- constraints << 'primary key' if column['primary-key']
143
+ constraints << 'not null' if column['required'] && !column['serial'] && !column['ident']
144
+ constraints << 'primary key' if column['ident']
144
145
  constraints << 'unique' if column['unique']
145
146
 
146
147
  #
@@ -150,7 +151,9 @@ create table <%= _(table['name']) %> (
150
151
  type_part = '%-20s' % type
151
152
  const_part = constraints.join(' ')
152
153
  comma = flag_last_loop ? '' : ','
153
- comment = column['ref'] ? " -- references #{column['ref']}" : ""
154
+ #comment = column['ref'] ? " -- references #{column['ref']}" : ""
155
+ ref = column['ref']
156
+ comment = ref ? " -- references #{ref['table']['name']}(#{ref['name']})" : ""
154
157
  %>
155
158
  <%= name_part %> <%= type_part %> <%= const_part %><%= comma %><%= comment %>
156
159
 
@@ -4,11 +4,12 @@
4
4
  ## kwatable template file for PostgreSQL
5
5
  ##
6
6
  ## copyright(c) 2005 kuwata-lab.com all rights reserved.
7
- ## $Release: 0.0.1 $
8
- ## $Rev: 12 $
7
+ ## $Release: 0.1.0 $
8
+ ## $Rev: 15 $
9
9
  ##
10
10
  ## template properties:
11
11
  ## (none)
12
+ ##
12
13
 
13
14
 
14
15
  #
@@ -47,15 +48,15 @@
47
48
  vacuum varchar verbose
48
49
  when where
49
50
  END
50
- KEYWORDS = {}
51
- keywords.split(/\s+/).each { |word| KEYWORDS[word] = true }
51
+ @keywords = {}
52
+ keywords.split(/\s+/).each { |word| @keywords[word] = true }
52
53
 
53
54
 
54
55
  #
55
56
  # escape keyword
56
57
  #
57
- def _(word)
58
- return KEYWORDS[word.downcase] ? "\"#{word}\"" : word
58
+ def self._(word)
59
+ return @keywords[word.downcase] ? "\"#{word}\"" : word
59
60
  end
60
61
 
61
62
 
@@ -122,10 +123,13 @@ create table <%= _(table['name']) %> (
122
123
  # constraints
123
124
  #
124
125
  constraints = []
125
- constraints << 'not null' if column['not-null'] && !column['serial'] && !column['primary-key']
126
- constraints << 'primary key' if column['primary-key']
126
+ constraints << 'not null' if column['required'] && !column['serial'] && !column['ident']
127
+ constraints << 'primary key' if column['ident']
127
128
  constraints << 'unique' if column['unique']
128
- constraints << "references #{column['ref-table']['name']}(#{column['ref-column']['name']})" if column['ref-table']
129
+ #constraints << "references #{column['ref-table']['name']}(#{column['ref-column']['name']})" if column['ref-table']
130
+ ref = column['ref']
131
+ constraints << "references #{ref['table']['name']}(#{ref['name']})" if ref
132
+
129
133
 
130
134
  #
131
135
  # column definition
@@ -134,7 +138,7 @@ create table <%= _(table['name']) %> (
134
138
  type_part = '%-20s' % type
135
139
  const_part = constraints.join(' ')
136
140
  comma = flag_last_loop ? '' : ','
137
- comment = column['values'] ? " -- #{column['values'].join(',')}" : ""
141
+ comment = column['enum'] ? " -- #{column['enum'].join(',')}" : ""
138
142
  %>
139
143
  <%= name_part %> <%= type_part %> <%= const_part %><%= comma %><%= comment %>
140
144
 
@@ -3,8 +3,8 @@
3
3
  ##
4
4
  ## copyright(c) 2005 kuwata-lab all rights reserverd
5
5
  ##
6
- ## $Id: defaults.yaml 11 2005-09-11 13:15:45Z kwatch $
7
- ## $Release: 0.0.1 $
6
+ ## $Id: defaults.yaml 13 2005-09-15 00:21:25Z kwatch $
7
+ ## $Release: 0.1.0 $
8
8
  ##
9
9
 
10
10
  columns:
@@ -63,14 +63,14 @@ columns:
63
63
  - name: gender
64
64
  type: char
65
65
  width: 1
66
- values:
66
+ enum:
67
67
  - M
68
68
  - F
69
69
 
70
70
  - name: blood
71
71
  type: char
72
72
  width: 2
73
- values:
73
+ enum:
74
74
  - A
75
75
  - B
76
76
  - O
@@ -4,12 +4,13 @@
4
4
  ## kwatable template file for Java DTO class
5
5
  ##
6
6
  ## copyright(c) 2005 kuwata-lab.com all rights reserved.
7
- ## $Release: 0.0.1 $
8
- ## $Rev: 12 $
7
+ ## $Release: 0.1.0 $
8
+ ## $Rev: 15 $
9
9
  ##
10
10
  ## template properties:
11
11
  ## package - package name
12
12
  ## parent - parent class
13
+ ##
13
14
 
14
15
 
15
16
  #
@@ -20,46 +21,43 @@
20
21
  raise "option '-m' is required when using 'dto-java.eruby'." unless table
21
22
 
22
23
 
23
- unless defined?(KEYWORDS)
24
- #
25
- # java keywords
26
- #
27
- keywords = <<-END
28
- abstract boolean break byte case catch char class const
29
- continue default do double else extends final finally float
30
- for goto if implements import instanceof int interface long
31
- native new package private protected public return short
32
- static strictfp super switch synchronized this throw throws
33
- transient try void volatile while
34
- END
35
- KEYWORDS = {}
36
- keywords.split(/\s+/).each { |word| KEYWORDS[word] = true }
37
-
38
-
39
- #
40
- # escape java keywords
41
- #
42
- def _(word)
43
- return KEYWORDS[word] ? "_#{word}" : word
44
- end
24
+ #
25
+ # java keywords
26
+ #
27
+ keywords = <<-END
28
+ abstract assert boolean break byte case catch char class const
29
+ continue default do double else enum extends final finally float
30
+ for goto if implements import instanceof int interface long
31
+ native new package private protected public return short
32
+ static strictfp super switch synchronized this throw throws
33
+ transient try void volatile while
34
+ END
35
+ @keywords = {}
36
+ keywords.split(/\s+/).each { |word| @keywords[word] = true }
45
37
 
46
38
 
47
- #
48
- # convert 'aaa_bbb_ccc' into 'AaaBbbCcc'
49
- #
50
- def camel_case(name, flag_all=true)
51
- s = ''
52
- name.split('_').each_with_index do |word, i|
53
- s << (!flag_all && i == 0 ? word.downcase : word.capitalize)
54
- end
55
- return s
56
- #s = name.split('_').collect { |w| w.capitalize }.join()
57
- #s[0] = s[0].to_s.upcase.chr unless flag_all
58
- end
39
+ #
40
+ # escape java keywords
41
+ #
42
+ def self._(word)
43
+ return @keywords[word] ? "_#{word}" : word
44
+ end
45
+
59
46
 
47
+ #
48
+ # convert 'aaa_bbb_ccc' into 'AaaBbbCcc'
49
+ #
50
+ def self.camel_case(name, flag_all=true)
51
+ s = ''
52
+ name.split('_').each_with_index do |word, i|
53
+ s << (!flag_all && i == 0 ? word.downcase : word.capitalize)
54
+ end
55
+ return s
56
+ #s = name.split('_').collect { |w| w.capitalize }.join()
57
+ #s[0] = s[0].to_s.upcase.chr unless flag_all
60
58
  end
61
-
62
-
59
+
60
+
63
61
  #
64
62
  # class definition
65
63
  #
@@ -69,7 +67,7 @@
69
67
  :parent => table['parent'] || properties[:parent],
70
68
  :desc => table['desc'],
71
69
  }
72
-
70
+
73
71
 
74
72
  #
75
73
  # output file name
@@ -135,24 +133,20 @@ public class <%= klass[:name] %><%= extends %> implements java.io.Serializable {
135
133
  #
136
134
  # instance variables
137
135
  #
138
- for var in variables
139
- vartype = '%-12s' % var[:type]
140
- varname = '%-12s' % (var[:name]+';')
141
- %>
142
- private <%= vartype %> <%= _(varname) %> /* <%= var[:desc] %> */
143
- <%
144
- end
145
136
  %>
137
+ <% for var in variables %>
138
+ <% varname = '%-12s' % ( _(var[:name]) + ';') %>
139
+ private <%= '%-12s' % var[:type] %> <%= varname %> /* <%= var[:desc] %> */
140
+ <% end %>
146
141
 
147
142
  <%
148
143
  #
149
- # constructor
144
+ # populator with java.sql.ResultSet
150
145
  #
151
- argstr = variables.collect { |var| "#{var[:type]} #{_(var[:name])}" }.join(', ')
152
146
  %>
153
- public <%= klass[:name] %>(<%= argstr %>) {
147
+ public void populate(java.sql.ResultSet resultset) {
154
148
  <% for var in variables %>
155
- this.<%= _(var[:name]) %> = <%= _(var[:name]) %>;
149
+ set<%= camel_case(var[:name]) %>(resultset.get<%= var[:type].capitalize %>("<%= var[:name] %>"));
156
150
  <% end %>
157
151
  }
158
152
 
@@ -169,19 +163,15 @@ public class <%= klass[:name] %><%= extends %> implements java.io.Serializable {
169
163
  public <%= vartype %> <%= getter %>() { return <%= _(varname) %> }
170
164
  public void <%= setter %>(<%= vartype %> <%= _(varname) %>) { this.<%= _(varname) %> = <%= _(varname) %>; }
171
165
 
172
- <%
173
- end
174
- %>
175
- // -----------
176
-
166
+ <% end %>
177
167
  <%
178
168
  #
179
169
  # foreign keys
180
170
  #
181
171
  for column in table['columns']
182
- if column['ref-table']
183
- reftype = column['ref-table']['class']
184
- refcol = column['ref-column']['name']
172
+ if column['ref']
173
+ reftype = column['ref']['table']['class']
174
+ refcolname = column['ref']['name']
185
175
  refname = column['ref-name']
186
176
  varname = column['name']
187
177
  if refname == varname
@@ -194,7 +184,7 @@ public class <%= klass[:name] %><%= extends %> implements java.io.Serializable {
194
184
  public <%= reftype %> <%= getter %>() { return <%= _(refname) %>; }
195
185
  public void <%= setter %>(<%= reftype %> <%= _(refname) %>) {
196
186
  this.<%= _(refname) %> = <%= _(refname) %>;
197
- this.<%= _(varname) %> = <%= _(refname) %>.get<%= camel_case(refcol) %>();
187
+ this.<%= _(varname) %> = <%= _(refname) %>.get<%= camel_case(refcolname) %>();
198
188
  }
199
189
 
200
190
  <%