ezframe 0.0.1

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 (65) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +12 -0
  3. data/.rubocop.yml +44 -0
  4. data/Gemfile +5 -0
  5. data/README.md +37 -0
  6. data/Rakefile +6 -0
  7. data/example/auth/Gemfile +8 -0
  8. data/example/auth/asset/css/materialize.min.css +13 -0
  9. data/example/auth/asset/js/common.js +200 -0
  10. data/example/auth/asset/js/htmlgen.js +79 -0
  11. data/example/auth/columns/user.yml +12 -0
  12. data/example/auth/config.ru +26 -0
  13. data/example/auth/config/view_conf.yml +3 -0
  14. data/example/auth/pages/app.rb +61 -0
  15. data/example/auth/template/base.html +12 -0
  16. data/example/chat/Gemfile +9 -0
  17. data/example/chat/asset/css/materialize.min.css +13 -0
  18. data/example/chat/asset/js/common.js +200 -0
  19. data/example/chat/asset/js/htmlgen.js +79 -0
  20. data/example/chat/columns/belong.yml +6 -0
  21. data/example/chat/columns/channel.yml +3 -0
  22. data/example/chat/columns/talk.yml +6 -0
  23. data/example/chat/columns/user.yml +12 -0
  24. data/example/chat/config.ru +23 -0
  25. data/example/chat/config/view_conf.yml +3 -0
  26. data/example/chat/pages/app.rb +59 -0
  27. data/example/chat/template/base.html +12 -0
  28. data/example/todo/Gemfile +8 -0
  29. data/example/todo/asset/css/datatable.css +54 -0
  30. data/example/todo/asset/css/materialize.min.css +13 -0
  31. data/example/todo/asset/js/common.js +135 -0
  32. data/example/todo/asset/js/datatable.js +1814 -0
  33. data/example/todo/asset/js/htmlgen.js +79 -0
  34. data/example/todo/asset/js/init.js +3 -0
  35. data/example/todo/asset/js/materialize.min.js +6 -0
  36. data/example/todo/asset/js/mydatatable.js +9 -0
  37. data/example/todo/asset/js/mymaterialize.js +22 -0
  38. data/example/todo/columns/todo.yml +9 -0
  39. data/example/todo/config.ru +15 -0
  40. data/example/todo/config/view_conf.yml +3 -0
  41. data/example/todo/pages/app.rb +93 -0
  42. data/example/todo/template/base.html +12 -0
  43. data/exe/console +14 -0
  44. data/exe/create_table.rb +11 -0
  45. data/exe/myrackup +5 -0
  46. data/ezframe.gemspec +43 -0
  47. data/lib/ezframe.rb +28 -0
  48. data/lib/ezframe/auth.rb +68 -0
  49. data/lib/ezframe/column_set.rb +174 -0
  50. data/lib/ezframe/column_type.rb +220 -0
  51. data/lib/ezframe/config.rb +33 -0
  52. data/lib/ezframe/controller.rb +63 -0
  53. data/lib/ezframe/database.rb +48 -0
  54. data/lib/ezframe/hthash.rb +116 -0
  55. data/lib/ezframe/html.rb +84 -0
  56. data/lib/ezframe/materialize.rb +109 -0
  57. data/lib/ezframe/model.rb +54 -0
  58. data/lib/ezframe/page_base.rb +109 -0
  59. data/lib/ezframe/page_kit.rb +84 -0
  60. data/lib/ezframe/pages.rb +8 -0
  61. data/lib/ezframe/server.rb +15 -0
  62. data/lib/ezframe/template.rb +25 -0
  63. data/lib/ezframe/util.rb +86 -0
  64. data/lib/ezframe/version.rb +3 -0
  65. metadata +236 -0
@@ -0,0 +1,220 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Ezframe
4
+ class TypeBase
5
+ attr_accessor :attribute, :parent
6
+ attr_writer :value
7
+
8
+ def self.get_class(key)
9
+ return nil unless key
10
+ upper = Object.const_get("Ezframe")
11
+ key_camel = "#{key}_type".to_camel
12
+ # puts "get_class: #{key_camel}"
13
+ # puts "const_get: #{upper.const_get(key_camel).inspect}"
14
+ if upper.const_defined?(key_camel)
15
+ return upper.const_get(key_camel)
16
+ end
17
+ return nil
18
+ end
19
+
20
+ def self.type_name
21
+ if /::(\w*)Type/ =~ to_s
22
+ return $1.to_s.to_snake
23
+ end
24
+ to_s.to_snake
25
+ end
26
+
27
+ def initialize(attr = nil)
28
+ @attribute = attr if attr
29
+ end
30
+
31
+ def key
32
+ @attribute[:key]
33
+ end
34
+
35
+ def label
36
+ return nil if @attribute[:hidden]
37
+ @attribute[:label]
38
+ end
39
+
40
+ def value(_situation = nil)
41
+ @value
42
+ end
43
+
44
+ def view
45
+ @value
46
+ end
47
+
48
+ def db_type
49
+ nil
50
+ end
51
+
52
+ def db_value
53
+ value
54
+ end
55
+
56
+ def form
57
+ nil
58
+ end
59
+ end
60
+
61
+ class StringType < TypeBase
62
+ def normalize
63
+ @value.gsub!(/ /, ' ')
64
+ end
65
+
66
+ def form
67
+ return nil if @attribute[:hidden] && !@attribute[:force]
68
+ { tag: 'input', type: 'text', name: @attribute[:key], key: @attribute[:key], label: @attribute[:label], value: @value }
69
+ end
70
+
71
+ def db_type
72
+ "string"
73
+ end
74
+ end
75
+
76
+ class IntType < StringType
77
+ def view
78
+ return nil if @attribute[:hidden]
79
+ Util.add_comma(@value.to_i)
80
+ end
81
+
82
+ def form
83
+ return nil if @attribute[:hidden]
84
+ { tag: 'input', type: 'number', key: @attribute[:key], label: @attribute[:label], value: @value }
85
+ end
86
+
87
+ def db_type
88
+ "int"
89
+ end
90
+ end
91
+
92
+ class ForeignType < IntType
93
+ def view
94
+ dataset = @parent.db.dataset[self.type.inner]
95
+ data = dataset.get(id: @value)
96
+ data[@attribute[:view]]
97
+ end
98
+ end
99
+
100
+ class IdType < IntType
101
+ def label
102
+ return nil if @attribute[:hidden] && !@attribute[:force]
103
+ "ID"
104
+ end
105
+ end
106
+
107
+ class PasswordType < StringType
108
+ def form
109
+ { tag: "input", type: "password", label: @attribute[:label], value: @value}
110
+ end
111
+
112
+ def db_value
113
+ value
114
+ end
115
+ end
116
+
117
+ class SelectType < TypeBase
118
+ def form
119
+ return nil if @attribute[:hidden]
120
+ { tag: 'select', key: @attribute[:key], label: @attribute[:label], items: @attribute[:items], value: @value }
121
+ end
122
+
123
+ def db_type
124
+ "string"
125
+ end
126
+ end
127
+
128
+ class CheckboxType < TypeBase
129
+ def form
130
+ return nil if @attribute[:hidden]
131
+ { tag: "checkbox", key: @attribute[:key], name: @attribute[:key], value: parent[:id].value, label: @attribute[:label] }
132
+ end
133
+
134
+ def db_type
135
+ "int"
136
+ end
137
+ end
138
+
139
+ class DateType < StringType
140
+ def form
141
+ h = super
142
+ h[:type] = 'date' if h
143
+ h
144
+ end
145
+
146
+ def db_type
147
+ "datetime"
148
+ end
149
+ end
150
+
151
+ class EmailType < StringType
152
+ def form
153
+ h = super
154
+ h[:type] = 'email' if h
155
+ h
156
+ end
157
+ end
158
+
159
+ class TelephoneType < StringType
160
+ def form
161
+ h = super
162
+ h[:type] = 'tel' if h
163
+ h
164
+ end
165
+ end
166
+
167
+ class JpnameType < StringType
168
+ end
169
+
170
+ class JpnameKanaType < StringType
171
+ def set(val)
172
+ val = val.tr('ァ-ン', 'ぁ-ん')
173
+ super(val)
174
+ end
175
+
176
+ def validation
177
+ unless /^[ぁ-ん ]+$/ =~ @value
178
+ 'ひらがなのみで入力してください。'
179
+ end
180
+ end
181
+ end
182
+
183
+ #
184
+ class PrefectureType < SelectType
185
+ def initialize(attr)
186
+ super(attr)
187
+ @pref_a = %w[選択してください 北海道 青森県 岩手県 宮城県 秋田県 山形県 福島県
188
+ 茨城県 栃木県 群馬県 埼玉県 千葉県 東京都 神奈川県
189
+ 新潟県 富山県 石川県 福井県 山梨県 長野県 岐阜県 静岡県 愛知県
190
+ 三重県 滋賀県 京都府 大阪府 兵庫県 奈良県 和歌山県
191
+ 鳥取県 島根県 岡山県 広島県 山口県
192
+ 徳島県 香川県 愛媛県 高知県
193
+ 福岡県 佐賀県 長崎県 熊本県 大分県 宮崎県 鹿児島県 沖縄県]
194
+ @pref_h = {}
195
+ @pref_a.each_with_index { |p, i| @pref_h[i] = p }
196
+ end
197
+
198
+ def form
199
+ h = super
200
+ h[:items] = @pref_h
201
+ h
202
+ end
203
+
204
+ def view
205
+ @pref_h[@value.to_i]
206
+ end
207
+ end
208
+
209
+ # Japanese Zipcode type column
210
+ class ZipcodeType < StringType
211
+ def view
212
+ return "" unless @value
213
+ @value.to_s.gsub(/(\d{3})(\d{4})/) { "#{$1}-#{$2}" }
214
+ end
215
+
216
+ def db_type
217
+ "string"
218
+ end
219
+ end
220
+ end
@@ -0,0 +1,33 @@
1
+ module Ezframe
2
+ class Config
3
+ class << self
4
+ attr_accessor :value_h
5
+
6
+ def load_files(dir)
7
+ Dir["#{dir}/*.yml"].each do |file|
8
+ load_one_file(file)
9
+ end
10
+ end
11
+
12
+ def load_one_file(filename)
13
+ begin
14
+ yaml = YAML.load_file(filename)
15
+ rescue
16
+ mylog("YAML load error: #{filename}")
17
+ return
18
+ end
19
+ @value_h ||={}
20
+ @value_h.update(yaml.recursively_symbolize_keys) if yaml.length>0
21
+ end
22
+
23
+ def [](k)
24
+ @value_h[k] if @value_h
25
+ end
26
+
27
+ def []=(k, v)
28
+ @value_h||={}
29
+ @value_h[k]=v
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,63 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Ezframe
4
+ class Boot
5
+ class << self
6
+ def exec(request, response)
7
+ @request = request
8
+ Config.load_files("./config")
9
+ Model.init
10
+ model = Model.get_clone
11
+ Auth.init_warden
12
+ Auth.model = model
13
+
14
+ mylog("exec: path=#{request.path_info} params=#{request.params}")
15
+ klass, method = PageBase::decide_route(request.path_info)
16
+ mylog "klass=#{klass}, method=#{method}"
17
+ page = klass.new(request, model)
18
+ if request.post?
19
+ method_full_name = "public_#{method}_post"
20
+ else
21
+ method_full_name = "public_#{method}_page"
22
+ end
23
+ warden.authenticate! if page.auth
24
+ # request.env["rack.session"]["kamatest"]="usable"
25
+ mylog "method: #{klass}.#{method_full_name}"
26
+ mylog "rack.session.id=#{request.env['rack.session'].id}"
27
+ mylog "rack.session.keys=#{request.env['rack.session'].keys}"
28
+ body = if page.respond_to?(method_full_name)
29
+ page.send(method_full_name)
30
+ else
31
+ mylog "no such method: #{method_full_name}"
32
+ page.public_default_page
33
+ end
34
+ if body.is_a?(Hash) || body.is_a?(Array)
35
+ response.body = [ JSON.generate(body) ]
36
+ response['Content-Type'] = 'application/json; charset=utf-8'
37
+ else
38
+ response.body = [ body ]
39
+ response['Content-Type'] = 'text/html; charset=utf-8'
40
+ end
41
+ response.status = 200
42
+ end
43
+
44
+
45
+ def file_not_found(response)
46
+ response.body = ['path not found']
47
+ response.status = 404
48
+ end
49
+
50
+ def warden
51
+ @request.env["warden"]
52
+ end
53
+
54
+ def login?
55
+ !!warden.user
56
+ end
57
+
58
+ def user
59
+ warden.user
60
+ end
61
+ end
62
+ end
63
+ end
@@ -0,0 +1,48 @@
1
+ # frozen_string_literal: true
2
+ require "logger"
3
+
4
+ module Ezframe
5
+ class Database
6
+ attr_accessor :sequel
7
+
8
+ def initialize(dbfile = "db/devel.sqlite")
9
+ @dbfile = dbfile
10
+ connect
11
+ end
12
+
13
+ def connect
14
+ @sequel = Sequel.connect("sqlite://#{@dbfile}", loggers: [Logger.new($stdout)])
15
+ end
16
+
17
+ def exec(sql)
18
+ @sequel.run(sql)
19
+ end
20
+
21
+ def dataset(table_name)
22
+ @sequel[table_name.to_sym]
23
+ end
24
+
25
+ def create_table(table_name, dbtype_h)
26
+ %w[id created_at updated_at].each do |key|
27
+ dbtype_h.delete(key.to_sym)
28
+ end
29
+ @sequel.create_table(table_name) do
30
+ primary_key :id, auto_increment: true
31
+ dbtype_h.each do |key, dbtype|
32
+ column(key, dbtype)
33
+ end
34
+ column(:created_at, :timestamp, default: Sequel::CURRENT_TIMESTAMP)
35
+ column(:updated_at, :timestamp, default: Sequel::CURRENT_TIMESTAMP)
36
+ end
37
+ end
38
+
39
+ def insert(table_name, val_h)
40
+ dataset(table_name).insert(val_h)
41
+ end
42
+
43
+ def update(dataset, val_h)
44
+ val_h.update({ updated_at: Time.now() })
45
+ dataset.update(val_h)
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,116 @@
1
+ module Ezframe
2
+ module Ht
3
+ class << self
4
+ def wrap_tag(opts = {})
5
+ h = opts.dup
6
+ raise "Ht.wrap_tag: value must be a hash: #{h}" unless h.is_a?(Hash)
7
+ h[:tag] = __callee__.to_s
8
+ h
9
+ end
10
+
11
+ alias_method :h1, :wrap_tag
12
+ alias_method :h2, :wrap_tag
13
+ alias_method :h3, :wrap_tag
14
+ alias_method :h4, :wrap_tag
15
+ alias_method :h5, :wrap_tag
16
+ alias_method :h6, :wrap_tag
17
+ alias_method :p, :wrap_tag
18
+ alias_method :br, :wrap_tag
19
+ alias_method :hr, :wrap_tag
20
+ alias_method :div, :wrap_tag
21
+ alias_method :span, :wrap_tag
22
+ alias_method :i, :wrap_tag
23
+ alias_method :strong, :wrap_tag
24
+ alias_method :ul, :wrap_tag
25
+ alias_method :ol, :wrap_tag
26
+ alias_method :li, :wrap_tag
27
+ alias_method :table, :wrap_tag
28
+ alias_method :thead, :wrap_tag
29
+ alias_method :tbody, :wrap_tag
30
+ alias_method :tr, :wrap_tag
31
+ alias_method :th, :wrap_tag
32
+ alias_method :td, :wrap_tag
33
+ alias_method :img, :wrap_tag
34
+ alias_method :a, :wrap_tag
35
+ alias_method :form, :wrap_tag
36
+ alias_method :button, :wrap_tag
37
+ alias_method :input, :wrap_tag
38
+ alias_method :select, :wrap_tag
39
+ alias_method :textarea, :wrap_tag
40
+ alias_method :label, :wrap_tag
41
+ alias_method :fieldset, :wrap_tag
42
+
43
+ alias_method :icon, :wrap_tag
44
+ alias_method :checkbox, :wrap_tag
45
+ alias_method :radio, :wrap_tag
46
+
47
+ def multi_wrap(class_a, child)
48
+ class_a.reverse.each do |klass|
49
+ child = Ht.div(class: klass, child: child)
50
+ end
51
+ return child
52
+ end
53
+ end
54
+
55
+ class List
56
+ attr_accessor :array
57
+
58
+ def initialize(tag: "ul", array: [])
59
+ @tag = tag
60
+ @array = array.dup
61
+ end
62
+
63
+ def to_hash
64
+ return nil if @list.nil? || @list.empty?
65
+ child = @array.map do |elem|
66
+ { tag: "li", child: elem }
67
+ end
68
+ { tag: @tag, child: child }
69
+ end
70
+ end
71
+
72
+ class Ul < List
73
+ def initialize(array: [])
74
+ super(tag: "ul", array: array)
75
+ end
76
+ end
77
+
78
+ class Ol < List
79
+ def initialize(array: [])
80
+ super(tag: "ol", array: array)
81
+ end
82
+ end
83
+
84
+ class Table
85
+ attr_accessor :class_a, :header
86
+
87
+ def initialize(matrix = nil)
88
+ set(matrix) if matrix
89
+ @matrix ||= []
90
+ end
91
+
92
+ def set(matrix)
93
+ @matrix = matrix
94
+ end
95
+
96
+ def add_row(row)
97
+ @matrix.push(row)
98
+ end
99
+
100
+ def to_hash
101
+ table_class, tr_class, td_class = @class_a
102
+ max_col = 0
103
+ @matrix.each { |row| max_col = row.length if max_col < row.length }
104
+ tr_a = @matrix.map do |row|
105
+ add_attr = nil
106
+ add_attr = { colspan: max_col - row.length + 1 } if row.length < max_col
107
+ td_a = row.map { |v| Ht.td(class: td_class, child: v) }
108
+ td_a[0].update(add_attr) if add_attr
109
+ Ht.tr(class: tr_class, child: td_a)
110
+ end
111
+ tr_a.unshift( Ht.thead(child: Ht.tr(child: @header.map {|v| Ht.th(child: v) }) )) if @header
112
+ Ht.table(class: table_class, child: tr_a)
113
+ end
114
+ end
115
+ end
116
+ end