ezframe 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +12 -0
- data/.rubocop.yml +44 -0
- data/Gemfile +5 -0
- data/README.md +37 -0
- data/Rakefile +6 -0
- data/example/auth/Gemfile +8 -0
- data/example/auth/asset/css/materialize.min.css +13 -0
- data/example/auth/asset/js/common.js +200 -0
- data/example/auth/asset/js/htmlgen.js +79 -0
- data/example/auth/columns/user.yml +12 -0
- data/example/auth/config.ru +26 -0
- data/example/auth/config/view_conf.yml +3 -0
- data/example/auth/pages/app.rb +61 -0
- data/example/auth/template/base.html +12 -0
- data/example/chat/Gemfile +9 -0
- data/example/chat/asset/css/materialize.min.css +13 -0
- data/example/chat/asset/js/common.js +200 -0
- data/example/chat/asset/js/htmlgen.js +79 -0
- data/example/chat/columns/belong.yml +6 -0
- data/example/chat/columns/channel.yml +3 -0
- data/example/chat/columns/talk.yml +6 -0
- data/example/chat/columns/user.yml +12 -0
- data/example/chat/config.ru +23 -0
- data/example/chat/config/view_conf.yml +3 -0
- data/example/chat/pages/app.rb +59 -0
- data/example/chat/template/base.html +12 -0
- data/example/todo/Gemfile +8 -0
- data/example/todo/asset/css/datatable.css +54 -0
- data/example/todo/asset/css/materialize.min.css +13 -0
- data/example/todo/asset/js/common.js +135 -0
- data/example/todo/asset/js/datatable.js +1814 -0
- data/example/todo/asset/js/htmlgen.js +79 -0
- data/example/todo/asset/js/init.js +3 -0
- data/example/todo/asset/js/materialize.min.js +6 -0
- data/example/todo/asset/js/mydatatable.js +9 -0
- data/example/todo/asset/js/mymaterialize.js +22 -0
- data/example/todo/columns/todo.yml +9 -0
- data/example/todo/config.ru +15 -0
- data/example/todo/config/view_conf.yml +3 -0
- data/example/todo/pages/app.rb +93 -0
- data/example/todo/template/base.html +12 -0
- data/exe/console +14 -0
- data/exe/create_table.rb +11 -0
- data/exe/myrackup +5 -0
- data/ezframe.gemspec +43 -0
- data/lib/ezframe.rb +28 -0
- data/lib/ezframe/auth.rb +68 -0
- data/lib/ezframe/column_set.rb +174 -0
- data/lib/ezframe/column_type.rb +220 -0
- data/lib/ezframe/config.rb +33 -0
- data/lib/ezframe/controller.rb +63 -0
- data/lib/ezframe/database.rb +48 -0
- data/lib/ezframe/hthash.rb +116 -0
- data/lib/ezframe/html.rb +84 -0
- data/lib/ezframe/materialize.rb +109 -0
- data/lib/ezframe/model.rb +54 -0
- data/lib/ezframe/page_base.rb +109 -0
- data/lib/ezframe/page_kit.rb +84 -0
- data/lib/ezframe/pages.rb +8 -0
- data/lib/ezframe/server.rb +15 -0
- data/lib/ezframe/template.rb +25 -0
- data/lib/ezframe/util.rb +86 -0
- data/lib/ezframe/version.rb +3 -0
- 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
|