ezframe 0.0.4 → 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (54) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile +2 -0
  3. data/README.md +1 -1
  4. data/asset/css/materialize.min.css +13 -0
  5. data/asset/css/style.css +3 -0
  6. data/asset/html/index.html +1 -0
  7. data/{app_template/asset/image/favicon.ico → asset/image/c_e.ico} +0 -0
  8. data/asset/js/ezframe.js +387 -0
  9. data/exe/check_column_yml +64 -0
  10. data/exe/console +2 -2
  11. data/exe/{create_table.rb → create_table} +7 -4
  12. data/exe/dbmigrate +174 -0
  13. data/exe/html2ruby +61 -0
  14. data/ezframe.gemspec +10 -8
  15. data/lib/ezframe.rb +9 -3
  16. data/lib/ezframe/auth.rb +50 -31
  17. data/lib/ezframe/column_set.rb +314 -103
  18. data/lib/ezframe/column_type.rb +456 -99
  19. data/lib/ezframe/config.rb +27 -6
  20. data/lib/ezframe/controller.rb +41 -38
  21. data/lib/ezframe/database.rb +171 -52
  22. data/lib/ezframe/editor_common.rb +74 -0
  23. data/lib/ezframe/email.rb +34 -0
  24. data/lib/ezframe/ezlog.rb +40 -0
  25. data/lib/ezframe/ht.rb +42 -17
  26. data/lib/ezframe/html.rb +47 -31
  27. data/lib/ezframe/japanese_utils.rb +15 -0
  28. data/lib/ezframe/jquery-ui.rb +29 -0
  29. data/lib/ezframe/loader.rb +4 -4
  30. data/lib/ezframe/main_editor.rb +19 -0
  31. data/lib/ezframe/main_page_kit.rb +226 -0
  32. data/lib/ezframe/materialize.rb +10 -14
  33. data/lib/ezframe/message.rb +46 -0
  34. data/lib/ezframe/page_base.rb +59 -71
  35. data/lib/ezframe/route.rb +126 -0
  36. data/lib/ezframe/server.rb +16 -5
  37. data/lib/ezframe/single_page_editor.rb +22 -0
  38. data/lib/ezframe/single_page_kit.rb +199 -0
  39. data/lib/ezframe/sub_editor.rb +25 -0
  40. data/lib/ezframe/sub_page_kit.rb +213 -0
  41. data/lib/ezframe/template.rb +5 -4
  42. data/lib/ezframe/util.rb +45 -23
  43. data/lib/ezframe/version.rb +1 -1
  44. metadata +74 -34
  45. data/.rubocop.yml +0 -44
  46. data/app_template/asset/js/ezframe.js +0 -288
  47. data/app_template/config.ru +0 -10
  48. data/app_template/config/generic.yml +0 -3
  49. data/app_template/config/materialize.yml +0 -5
  50. data/app_template/pages/basic.rb +0 -5
  51. data/exe/setup.rb +0 -15
  52. data/lib/ezframe/editor.rb +0 -188
  53. data/lib/ezframe/model.rb +0 -52
  54. data/lib/ezframe/page_kit.rb +0 -63
@@ -2,55 +2,192 @@
2
2
 
3
3
  module Ezframe
4
4
  class ColumnSets
5
- attr_accessor :tables, :model
6
-
7
- def initialize
8
- @tables = {}
9
- end
5
+ class << self
6
+ def init(dir = nil)
7
+ dir ||= "./column"
8
+ unless @colset_h
9
+ @colset_h = {}
10
+ load_files(dir)
11
+ end
12
+ end
10
13
 
11
- def load_files(dir)
12
- Dir["#{dir}/*.yml"].each do |filename|
13
- load_one_file(filename)
14
+ def load_files(dir)
15
+ Dir["#{dir}/*.yml"].each do |filename|
16
+ load_one_file(filename)
17
+ end
18
+ end
19
+
20
+ def load_one_file(filename)
21
+ colset_name = $1 if filename =~ /(\w+).ya?ml$/
22
+ yaml = YAML.load(File.open(filename), symbolize_names: true)
23
+ if yaml.length == 0
24
+ EzLog.error("[ERROR] columns file is empty: #{filename}")
25
+ return
26
+ end
27
+ column_info = yaml # .recursively_symbolize_keys
28
+ # puts "load_one_file: filename=#{filename} column_info=#{column_info.inspect}"
29
+ add(colset_name, column_info)
30
+ end
31
+
32
+ def add(colset_name, columns)
33
+ @colset_h[colset_name.to_sym] = cs = ColumnSet.new(parent: self, name: colset_name, columns: columns)
34
+ cs.set(columns)
35
+ return cs
36
+ end
37
+
38
+ def clone
39
+ @colset_h.deep_dup
40
+ end
41
+
42
+ def has_key?(key)
43
+ return nil unless key
44
+ return @colset_h[key.to_sym]
45
+ end
46
+
47
+ def get(colset_name)
48
+ return nil unless colset_name
49
+ return @colset_h[colset_name.to_sym].deep_dup
50
+ end
51
+
52
+ def refer(colset_name)
53
+ return nil unless colset_name
54
+ return @colset_h[colset_name.to_sym]
55
+ end
56
+
57
+ def [](colset_name)
58
+ return get(colset_name)
59
+ end
60
+
61
+ def each
62
+ @colset_h.each {|k, v| yield(k, v) }
63
+ end
64
+
65
+ def inspect
66
+ return @colset_h.map do |name, colset|
67
+ # "[#{name}]:#{colset.inspect}"
68
+ "[#{name}]:\n"
69
+ end.join
14
70
  end
15
- end
16
71
 
17
- def load_one_file(filename)
18
- table_name = $1 if filename =~ /(\w+).ya?ml$/
19
- begin
20
- yaml = YAML.load_file(filename)
21
- rescue
22
- mylog("YAML load error: #{filename}")
23
- return
72
+ def create_tables
73
+ self.each do |table_name, column_set|
74
+ begin
75
+ create_one_table(table_name, column_set)
76
+ rescue => e
77
+ EzLog.error("create_tables: #{e.inspect}\n#{$@.inspect}")
78
+ end
79
+ end
24
80
  end
25
- if yaml.length == 0
26
- mylog("[ERROR] columns file is empty: #{filename}")
27
- return
81
+
82
+ def create_one_table(table_name, column_set)
83
+ col_h = column_set.get_hash(:db_type)
84
+ EzLog.info "create_one_table: col_h=#{col_h.inspect}"
85
+ DB.create_table(table_name, col_h)
86
+ end
87
+
88
+ # foreignから生成したテーブル連結情報を返す
89
+ def full_join_structure(colset_id)
90
+ struct = { tables: [colset_id] }
91
+ colset = @colset_h[colset_id.to_sym]
92
+ colset_keys = colset.keys
93
+ struct[:column_list] = colset_keys.map { |k| "#{colset_id}.#{k}" }
94
+ join_cond_h = {}
95
+ colset_keys.each do |key|
96
+ column = colset[key]
97
+ if column.type.to_s == "foreign"
98
+ # 連結するテーブル名をtable: で指定する。
99
+ foreign_table = column.attribute[:table]
100
+ # 指定されてなければ、キーの名称をテーブル名とする
101
+ # そのテーブルが定義されてなければ、エラーとしてログに残す。
102
+ unless foreign_table
103
+ if @colset_h[key]
104
+ foreign_table = key
105
+ else
106
+ EzLog.error "There is no related table: #{key}"
107
+ next
108
+ end
109
+ end
110
+ raise "no table: key=#{key}" unless foreign_table
111
+ foreign_column = column.attribute[:column]&.to_sym || :id
112
+ foreign_table = foreign_table.to_sym
113
+ next if struct[:tables].include?(foreign_table)
114
+ # join_cond_h["#{colset_id}.#{key}"] = "#{colset_id}.#{key} = #{foreign_table}.#{foreign_column}"
115
+ join_cond_h[foreign_table] = "#{colset_id}.#{key} = #{foreign_table}.#{foreign_column}"
116
+ struct[:tables].push(foreign_table)
117
+ struct[:column_list] += ColumnSets.refer(foreign_table).keys.map {|k| "#{foreign_table}.#{k}" }
118
+ end
119
+ end
120
+ struct[:join_condition] = join_cond_h
121
+ return struct
122
+ end
123
+
124
+ def join_complex_column
125
+
28
126
  end
29
- column_info = yaml.recursively_symbolize_keys
30
- puts "load_one_file: filename=#{filename} column_info=#{column_info.inspect}"
31
- add(table_name, column_info)
32
127
  end
128
+ end
33
129
 
34
- def add(table_name, columns)
35
- @tables[table_name.to_sym] = tb = ColumnSet.new(parent: self, name: table_name, columns: columns)
36
- tb.set(columns)
130
+ # ColumnSetを複数組み合わせて扱う
131
+ class ColumnSetCollection
132
+ attr_accessor :colset_list
133
+
134
+ def initialize(default_table=nil)
135
+ @colset_h = {}
136
+ @default_table = default_table
37
137
  end
38
138
 
39
- def [](table_name)
40
- return @tables[table_name]
139
+ def values=(data)
140
+ @colset_h.each {|key, colset| colset.clear }
141
+ set_values(data)
41
142
  end
42
143
 
43
- def each
44
- @tables.each {|k, v| yield(k, v) }
144
+ def set_values(data)
145
+ data.each do |key, value|
146
+ if key.to_s.index(".")
147
+ table_key, col_key = key.to_s.split(".")
148
+ colset = @colset_h[table_key.to_sym]
149
+ unless colset
150
+ @colset_h[table_key.to_sym] = colset = ColumnSets[table_key]
151
+ end
152
+ elsif @default_table
153
+ col_key = key
154
+ colset = @colset_h[@default_table.to_sym]
155
+ unless colset
156
+ @colset_h[table_key.to_sym] = colset = ColumnSets[@default_table]
157
+ end
158
+ end
159
+ colset[col_key].value = value
160
+ end
161
+ end
162
+
163
+ def get(colset_key, col_key=nil)
164
+ if col_key.nil?
165
+ if colset_key.to_s.index(".")
166
+ colset_key, col_key = colset_key.to_s.split(".")
167
+ elsif @default_table
168
+ colset_key, col_key = @default_table, colset_key
169
+ else
170
+ EzLog.error "ColumnSetCollection.get: illegal arguments: #{colset_key}, #{col_key}"
171
+ return nil
172
+ end
173
+ end
174
+ colset = @colset_h[colset_key.to_sym]
175
+ return nil unless colset
176
+ # EzLog.debug("Collection.get: colset_key=#{colset_key}, col_key=#{col_key}, value=#{colset[col_key].value}")
177
+ return colset[col_key]
178
+ end
179
+
180
+ def [](k)
181
+ return get(k)
45
182
  end
46
183
  end
47
184
 
48
185
  class ColumnSet
49
- attr_accessor :name, :parent, :edit_keys, :view_keys
186
+ attr_accessor :name, :parent # , :edit_keys, :view_keys
50
187
 
51
- def initialize(parent:, name: nil, columns: nil)
188
+ def initialize(parent: nil, name: nil, columns: nil)
52
189
  @parent = parent
53
- @name = name
190
+ @name = name
54
191
  @columns ||= {}
55
192
  set(columns) if columns
56
193
  end
@@ -61,10 +198,23 @@ module Ezframe
61
198
  end
62
199
  end
63
200
 
201
+ def keys
202
+ @columns.keys
203
+ end
204
+
205
+ def edit_keys
206
+ @columns.keys.select {|k| !@columns[k].no_edit? }
207
+ end
208
+
209
+ def view_keys
210
+ @columns.keys.select {|k| !@columns[k].no_view? }
211
+ end
212
+
213
+ # 配列を初期化する
64
214
  def set(attr_a)
65
- @columns[:id] = IdType.new(key: "id", label: "ID", no_edit: true)
66
- attr_a.each do |attributes|
67
- attr = attributes.clone
215
+ @columns[:id] = IdType.new(key: "id", label: "ID", hidden: true)
216
+ attr_a.each do |attribute|
217
+ attr = attribute.clone
68
218
  col_key = attr[:key]
69
219
  raise "no column key: #{attr.inspect}" unless col_key
70
220
  klass = TypeBase.get_class(attr[:type])
@@ -74,97 +224,147 @@ module Ezframe
74
224
  @columns[col_key.to_sym] = klass.new(attr)
75
225
  end
76
226
  end
77
- @columns[:created_at] = DatetimeType.new(type: "datetime", key: "created_at", label: "生成日時", no_edit: true)
78
- @columns[:updated_at] = DatetimeType.new(type: "datetime", key: "updated_at", label: "更新日時", no_edit: true)
79
- # mylog "set: #{@columns.inspect}"
80
- @columns.values.each {|col| col.parent = self }
227
+ @columns[:created_at] = DatetimeType.new(type: "datetime", key: "created_at", label: "生成日時", hidden: true)
228
+ @columns[:updated_at] = DatetimeType.new(type: "datetime", key: "updated_at", label: "更新日時", hidden: true)
229
+ @columns[:deleted_at] = DatetimeType.new(type: "datetime", key: "deleted_at", label: "削除日時", hidden: true)
230
+ @columns.values.each { |col| col.parent = self }
81
231
  return @columns
82
232
  end
83
233
 
84
234
  def dataset
85
- # puts "dataset: #{@model.inspect}"
86
- return @parent.model.db.dataset(@name)
235
+ return DB.dataset(@name)
87
236
  end
88
237
 
89
238
  def set_from_db(id)
90
239
  data = dataset.where(id: id).first
91
240
  return nil unless data
92
- self.values = data
241
+ self.set_values(data, from_db: true)
93
242
  return data
94
243
  end
95
244
 
96
- def save
97
- col_h = get_hash(:value)
98
- col_h.delete(:id)
99
- col_h.delete(:created_at)
100
- col_h[:updated_at] = Time.now
101
- mylog "save: #{col_h.inspect}"
102
- id = @columns[:id]
103
- if id.value.to_i > 0
104
- dataset.where(id: id.value).update(col_h)
245
+ def set_from_form(form, key_suffix: nil)
246
+ self.set_values(form)
247
+ end
248
+
249
+ # データベースに新規に値を登録する
250
+ def create(value_h, from_db: nil, key_suffix: nil)
251
+ if from_db
252
+ self.set_values(value_h, from_db: true, key_suffix: key_suffix)
105
253
  else
106
- return dataset.insert(col_h)
254
+ self.set_values(value_h, key_suffix: key_suffix)
107
255
  end
256
+ db_value_h = self.get_hash(:db_value)
257
+ EzLog.debug("column_set.create: #{db_value_h}")
258
+ db_value_h.delete(:id)
259
+ db_value_h[:updated_at] = Time.now
260
+ db_value_h[:created_at] = Time.now
261
+ EzLog.debug("create: sql=#{dataset.insert_sql(db_value_h)}")
262
+ return dataset.insert(db_value_h)
108
263
  end
109
264
 
265
+ # データベース上の値の更新
110
266
  def update(id, value_h)
111
- values = {}
112
- colkeys = @columns.keys
113
- value_h.each do |k, v|
114
- values[k] = v if colkeys.include?(k)
267
+ self.set_from_db(id)
268
+ updated_values = {}
269
+ @columns.each do |colkey, column|
270
+ next if column.no_edit?
271
+ if column.respond_to?(:form_to_value)
272
+ new_value = column.form_to_value(value_h)
273
+ else
274
+ new_value = value_h[colkey]
275
+ end
276
+ prev_value = column.db_value
277
+ column.value = new_value
278
+ # EzLog.debug("key=#{colkey}, pre_value=#{prev_value}, new_value=#{column.db_value}")
279
+ if column.respond_to?("value_equal?")
280
+ unless column.value_equal?(prev_value, column.db_value)
281
+ updated_values[colkey] = column.db_value
282
+ end
283
+ elsif prev_value != column.db_value
284
+ updated_values[colkey] = column.db_value
285
+ end
286
+ end
287
+ if updated_values.length > 0
288
+ updated_values[:updated_at] = Time.now
289
+ sql = dataset.where(id: id).update_sql(updated_values)
290
+ EzLog.debug("update: sql=#{sql}")
291
+ dataset.where(id: id).update(updated_values)
115
292
  end
116
- dataset.where(id: id).update(values)
117
- set_values(values)
118
293
  end
119
294
 
120
- def values=(value_h)
121
- clear
122
- set_values(value_h)
295
+ # 各カラムに値を格納する
296
+ def set_values(value_h, from_db: nil, key_suffix: nil)
297
+ self.clear
298
+ merge_values(value_h, from_db: from_db, key_suffix: key_suffix)
123
299
  end
124
300
 
125
- def set_values(value_h)
126
- return unless value_h
127
- value_h.each do |k, v|
128
- col = @columns[k.to_sym]
129
- next unless col
130
- col.value = v
301
+ def merge_values(value_h, from_db: nil, key_suffix: nil)
302
+ return self unless value_h
303
+ @columns.keys.each do |key|
304
+ next if key.to_s.empty?
305
+ target_key = key
306
+ target_key = "#{key}#{key_suffix}" if key_suffix
307
+ column = @columns[key.to_sym]
308
+ if !from_db && column.respond_to?(:form_to_value) # && !value_h.has_key?(key)
309
+ val = column.form_to_value(value_h, target_key: target_key)
310
+ else
311
+ val = value_h[target_key.to_sym] || value_h[key]
312
+ end
313
+ column.value = val
131
314
  end
315
+ return self
316
+ end
317
+
318
+ def values=(value_h)
319
+ set_values(value_h)
132
320
  end
133
321
 
134
- def validate
322
+ # 各カラムのバリデーション
323
+ # 戻り値は[ 正規化した値, エラーシンボル(Messageのキーと紐づく) ]を値として、
324
+ # カラムキーをキーとするハッシュ
325
+ def validate(value_h)
326
+ return {} unless value_h
135
327
  clear_error
136
- errors = []
137
- @columns.values.each do |col|
138
- err = col.validate
139
- errors.push([ col.key, err ]) if err
328
+ result_h = {}
329
+ @columns.values.each do |col|
330
+ res = []
331
+ if col.respond_to?(:form_to_value) && !value_h.has_key?(col.key)
332
+ orig_val = col.form_to_value(value_h)
333
+ else
334
+ orig_val = value_h[col.key]
335
+ end
336
+ new_val = col.normalize(orig_val)
337
+ res[0] = new_val if orig_val != new_val
338
+ res[1] = col.validate(new_val)
339
+ result_h[col.key] = res if res[0] || res[1]
140
340
  end
141
- return errors
341
+ return result_h
142
342
  end
143
343
 
144
344
  def clear_error
145
- @columns.values.each {|col| col.error = nil }
345
+ @columns.values.each { |col| col.error = nil }
146
346
  end
147
347
 
148
348
  def values
149
- @columns.map {|key, col| col.value}
150
- end
349
+ @columns.map { |key, col| col.value }
350
+ end
151
351
 
152
352
  def each
153
- @columns.values.each {|column| yield(column) }
353
+ @columns.values.each { |column| yield(column) }
154
354
  end
155
355
 
156
356
  def map
157
- @columns.values.map {|column| yield(column) }
357
+ @columns.values.map { |column| yield(column) }
158
358
  end
159
359
 
160
360
  def get_matrix(method_a)
161
361
  return @columns.map do |_key, col|
162
- method_a.map { |method| col.send(method) }
163
- end
362
+ method_a.map { |method| col.send(method) }
363
+ end
164
364
  end
165
365
 
166
366
  def get_hash(method)
167
- res_h = {}
367
+ res_h = {}
168
368
  @columns.map do |key, col|
169
369
  res_h[key.to_sym] = col.send(method)
170
370
  end
@@ -174,41 +374,52 @@ module Ezframe
174
374
  def [](col_key)
175
375
  return @columns[col_key.to_sym]
176
376
  end
177
-
377
+
178
378
  def form
179
379
  if @edit_keys
180
- return @edit_keys.map do |key|
181
- col = @columns[key.to_sym]
182
- unless col
183
- mylog "[ERROR] @edit_keys has unknown column:name=#{@name}:key=#{key}"
184
- next
185
- end
186
- col.form
187
- end
380
+ return @edit_keys.map do |key|
381
+ col = @columns[key.to_sym]
382
+ unless col
383
+ EzLog.info "[ERROR] @edit_keys has unknown column:name=#{@name}:key=#{key}"
384
+ next
385
+ end
386
+ col.form
387
+ end
188
388
  else
189
- return @columns.values.map {|coltype| coltype.form }
190
- end
389
+ return @columns.values.map { |coltype| coltype.form }
390
+ end
191
391
  end
192
392
 
193
393
  def view
194
394
  if @view_keys
195
- return @view_keys.map do |key|
196
- col = @columns[key.to_sym]
197
- unless col
198
- mylog "[ERROR] @view_keys has unknown column:name=#{@name}:key=#{key}"
199
- next
200
- end
201
- col.view
202
- end
395
+ return @view_keys.map do |key|
396
+ col = @columns[key.to_sym]
397
+ unless col
398
+ EzLog.info "[ERROR] @view_keys has unknown column:name=#{@name}:key=#{key}"
399
+ next
400
+ end
401
+ col.view
402
+ end
203
403
  else
204
- return @columns.values.map {|coltype| coltype.view }
404
+ return @columns.values.map { |coltype| coltype.view }
205
405
  end
206
406
  end
207
407
 
408
+ def get_full_join(opts = {})
409
+ struct = ColumnSets.full_join_structure(self.name)
410
+ return DB.get_join_table(struct, opts)
411
+ end
412
+
208
413
  def hidden_form
209
414
  return @columns.map do |colkey, coltype|
210
- { tag: 'input', id: colkey, name: colkey, type: 'hidden', value: coltype.value }
211
- end
415
+ { tag: "input", id: colkey, name: colkey, type: "hidden", value: coltype.value }
416
+ end
417
+ end
418
+
419
+ def inpsect
420
+ @columns.map do |colkey, coltype|
421
+ "#{colkey}=#{coltype.value}"
422
+ end.join(" ")
212
423
  end
213
424
  end
214
425
  end