kwatable 0.0.1 → 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.
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
  <%