webink 2.1.1 → 3.0.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.
- data/bin/webink_database +5 -7
- data/bin/webink_init +47 -0
- data/lib/webink.rb +1 -0
- data/lib/webink/beauty.rb +168 -53
- data/lib/webink/controller.rb +40 -31
- data/lib/webink/database.rb +115 -46
- data/lib/webink/model.rb +91 -26
- metadata +7 -23
- data/bin/rfcgi +0 -143
data/bin/webink_database
CHANGED
@@ -1,28 +1,26 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
2
|
|
3
|
-
require '
|
4
|
-
require 'webink/beauty'
|
3
|
+
require 'webink'
|
5
4
|
|
6
5
|
config = nil
|
7
6
|
model_classes = Array.new
|
8
7
|
|
9
8
|
begin
|
10
|
-
config = Ink::Beauty.load_config
|
9
|
+
config = Ink::Beauty.new.load_config
|
11
10
|
rescue Exception => bang
|
12
11
|
puts "Error while loading config: #{bang}."
|
13
12
|
end
|
14
13
|
|
15
|
-
require "#{config[
|
16
|
-
require 'webink'
|
14
|
+
require "#{config[:db_type]}"
|
17
15
|
|
18
16
|
models = Dir.new "./models"
|
19
17
|
models.each do |model|
|
20
18
|
load "#{models.path}/#{model}" if model =~ /\.rb$/
|
21
|
-
model_classes
|
19
|
+
model_classes << Ink::Model.classname($1) if model =~ /^(.*)\.rb$/
|
22
20
|
end
|
23
21
|
|
24
22
|
begin
|
25
|
-
Ink::Database.create
|
23
|
+
Ink::Database.create(config)
|
26
24
|
db = Ink::Database.database
|
27
25
|
db_tables = db.tables
|
28
26
|
|
data/bin/webink_init
ADDED
@@ -0,0 +1,47 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
config_ru = <<CFG_RU
|
4
|
+
require 'erb'
|
5
|
+
require 'webink'
|
6
|
+
|
7
|
+
run Ink::Beauty.new
|
8
|
+
CFG_RU
|
9
|
+
|
10
|
+
config_rb = <<CFG_RB
|
11
|
+
Ink::Beauty.config = {
|
12
|
+
#sqlite3 config
|
13
|
+
:db_type => "sqlite3",
|
14
|
+
:db_server => "./db.sqlite",
|
15
|
+
|
16
|
+
#mysql config
|
17
|
+
#:db_type => "mysql"
|
18
|
+
#:db_user => "db_username"
|
19
|
+
#:db_pass => "db_password"
|
20
|
+
#:db_database => "db_database_name"
|
21
|
+
#:db_server => "localhost"
|
22
|
+
}
|
23
|
+
CFG_RB
|
24
|
+
|
25
|
+
routes_rb = <<RT_RB
|
26
|
+
Ink::Beauty.root = ""
|
27
|
+
|
28
|
+
Ink::Beauty.routes = [
|
29
|
+
[ /^\\/([^\\/]+)\\/([^\\/]+)\\/?$/, {:controller => "$1", :module => "$2"} ],
|
30
|
+
[ /^\\/([^\\/]+)\\/?$/, {:controller => "$1", :module => "index"} ],
|
31
|
+
[ /^\\/?$/, {:controller => "admin", :module => "index"} ],
|
32
|
+
]
|
33
|
+
RT_RB
|
34
|
+
|
35
|
+
if File.exist?("config") or File.exist?("config.rb")
|
36
|
+
puts "Directory already initialized. Exiting."
|
37
|
+
exit(0)
|
38
|
+
end
|
39
|
+
|
40
|
+
File.open("config.ru", "w"){ |f| f.puts config_ru }
|
41
|
+
File.open("config.rb", "w"){ |f| f.puts config_rb }
|
42
|
+
File.open("routes.rb", "w"){ |f| f.puts routes_rb }
|
43
|
+
Dir.mkdir("controllers", 0775)
|
44
|
+
Dir.mkdir("models", 0775)
|
45
|
+
Dir.mkdir("views", 0775)
|
46
|
+
Dir.mkdir("files", 0775)
|
47
|
+
File.chmod(0775, "config.ru", "config.rb", "routes.rb")
|
data/lib/webink.rb
CHANGED
data/lib/webink/beauty.rb
CHANGED
@@ -3,78 +3,193 @@ module Ink
|
|
3
3
|
# = Beauty class
|
4
4
|
#
|
5
5
|
# This class provides a set of tools for loading config and init scripts
|
6
|
-
# as well as the route-matching.
|
7
|
-
# beautiful, hence the name.
|
8
|
-
#
|
9
|
-
#
|
6
|
+
# as well as the route-matching. Formerly it made the dispatcher code
|
7
|
+
# much more beautiful, hence the name.
|
8
|
+
# Since 3.0.0 it handles the dispatching for rack and serves static files
|
9
|
+
# from ./files/*
|
10
|
+
#
|
11
|
+
#
|
10
12
|
#
|
11
13
|
class Beauty
|
12
|
-
|
13
|
-
# Class
|
14
|
-
#
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
14
|
+
|
15
|
+
# Class accessor definitions
|
16
|
+
#
|
17
|
+
class << self
|
18
|
+
attr_accessor :routes, :config, :root
|
19
|
+
end
|
20
|
+
|
21
|
+
# Constructor
|
22
|
+
#
|
23
|
+
def initialize
|
24
|
+
@params = {}
|
25
|
+
end
|
26
|
+
|
27
|
+
# Instance method
|
28
|
+
#
|
29
|
+
# Rackup call
|
30
|
+
# Initializes the webink environment
|
31
|
+
# Rescues all kinds of errors and responds with error codes
|
32
|
+
# [param env:] rack environment
|
33
|
+
# [returns:] Rack-compatible array
|
34
|
+
def call(env)
|
35
|
+
@params = {} #reset
|
36
|
+
@env = env
|
37
|
+
controller = self.init
|
38
|
+
if controller and not @params[:file]
|
39
|
+
Ink::Database.create(@params[:config])
|
40
|
+
response = controller.verify(@params[:module]).call
|
41
|
+
Ink::Database.database.close
|
42
|
+
response || [404, {}, self.error_mapping(404)]
|
43
|
+
elsif File.exist?("."+@params[:file])
|
44
|
+
[ 200, {}, File.open("."+@params[:file], File::RDONLY) ]
|
45
|
+
else
|
46
|
+
[ 404, {}, self.error_mapping(404) ]
|
47
|
+
end
|
48
|
+
rescue LoadError => bang
|
49
|
+
render_error(404, "LoadError", bang)
|
50
|
+
rescue NotImplementedError => bang
|
51
|
+
render_error(500, "NotImplementedError", bang)
|
52
|
+
rescue ArgumentError => bang
|
53
|
+
render_error(500, "ArgumentError", bang)
|
54
|
+
rescue RuntimeError => bang
|
55
|
+
render_error(500, "RuntimeError", bang)
|
56
|
+
rescue NameError => bang
|
57
|
+
render_error(500, "NameError", bang)
|
58
|
+
rescue Exception, Error => bang
|
59
|
+
render_error(500, "Exception", bang)
|
60
|
+
end
|
61
|
+
|
62
|
+
# Instance method
|
63
|
+
#
|
64
|
+
# Loads models and the controller. Requires the database type.
|
65
|
+
# [returns:] Controller class
|
66
|
+
def load_env
|
67
|
+
require "#{@params[:config][:db_type]}"
|
68
|
+
Dir.new("./models").each{ |m| load "./models/#{m}" if m =~ /\.rb$/ }
|
69
|
+
load "./controllers/#{@params[:controller]}.rb"
|
70
|
+
Ink::Controller.verify(@params[:controller]).new(@params)
|
71
|
+
end
|
72
|
+
|
73
|
+
# Instance method
|
74
|
+
#
|
75
|
+
# Generates a param hash including the config, route and get/post
|
76
|
+
# parameters.
|
77
|
+
# [returns:] Controller class
|
78
|
+
def init
|
79
|
+
req = Rack::Request.new(@env)
|
80
|
+
@params.merge!({:header => {}, :cookie => req.cookies})
|
81
|
+
@params[:get] = Rack::Utils.parse_query(@env["QUERY_STRING"], '&;') || {}
|
82
|
+
@params[:post] = {}
|
83
|
+
if @env['rack.input'].is_a?(StringIO)
|
84
|
+
@params[:post] =
|
85
|
+
Rack::Utils.parse_query(@env['rack.input'].read, "&;\n")
|
86
|
+
end
|
87
|
+
self.load_config
|
88
|
+
self.load_routes
|
89
|
+
@params[:file] ? nil : self.load_env #static file requests are nil
|
23
90
|
end
|
24
|
-
|
25
|
-
#
|
26
|
-
#
|
91
|
+
|
92
|
+
# Instance method
|
93
|
+
#
|
27
94
|
# Attempts to load the config file of the project or raises a LoadError.
|
28
|
-
# Once loaded, the config is
|
29
|
-
# it is returned
|
30
|
-
# [param script:] Project folder path
|
95
|
+
# Once loaded, the config is returned
|
31
96
|
# [returns:] a valid config
|
32
|
-
def
|
33
|
-
config = "
|
34
|
-
config = "#{config}.rb"
|
35
|
-
raise LoadError.new("Config not found.")
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
config
|
97
|
+
def load_config
|
98
|
+
config = "./config"
|
99
|
+
config = "#{config}.rb" unless File.exist?(config)
|
100
|
+
raise LoadError.new("Config not found.") unless File.exist?(config)
|
101
|
+
load config
|
102
|
+
if Beauty.config.nil?
|
103
|
+
raise LoadError.new("Config extension error on Beauty")
|
104
|
+
end
|
105
|
+
@params[:config] = Beauty.config
|
106
|
+
Beauty.config
|
41
107
|
end
|
42
|
-
|
43
|
-
#
|
44
|
-
#
|
45
|
-
# Attempts to load the routes file of the project or raises a LoadError
|
46
|
-
#
|
47
|
-
|
48
|
-
|
49
|
-
routes = "#{File.
|
50
|
-
|
51
|
-
|
52
|
-
routes
|
108
|
+
|
109
|
+
# Instance method
|
110
|
+
#
|
111
|
+
# Attempts to load the routes file of the project or raises a LoadError.
|
112
|
+
# Determines and stores the current route in the @params
|
113
|
+
def load_routes
|
114
|
+
routes = "./routes"
|
115
|
+
routes = "#{routes}.rb" unless File.exist?(routes)
|
116
|
+
raise LoadError.new("Routes not found.") unless File.exist?(routes)
|
117
|
+
load routes
|
118
|
+
if Beauty.routes.nil?
|
119
|
+
raise LoadError.new("Route extension error on Beauty")
|
120
|
+
elsif Beauty.root.nil?
|
121
|
+
raise LoadError.new("Root extension error on Beuaty")
|
122
|
+
end
|
123
|
+
@params.merge!(self.routing(@env["REQUEST_PATH"])) if @env["REQUEST_PATH"]
|
53
124
|
end
|
54
|
-
|
55
|
-
#
|
56
|
-
#
|
125
|
+
|
126
|
+
# Instance method
|
127
|
+
#
|
57
128
|
# Attempts to match the params onto the routes and return the results in
|
58
129
|
# form of a Hash.
|
59
|
-
#
|
60
|
-
#
|
61
|
-
# [param
|
130
|
+
# Possible root route is extracted and routes matching to /files/* will
|
131
|
+
# be stored in the match.
|
132
|
+
# [param str:] Requested string
|
62
133
|
# [returns:] Hash of Symbol => String
|
63
|
-
def
|
134
|
+
def routing(str)
|
135
|
+
root = Beauty.root
|
136
|
+
root = $1 if root =~ /(.*)\/$/
|
64
137
|
match = { :root => root }
|
65
|
-
|
138
|
+
if str =~ /^#{root}(.*)\/?$/
|
139
|
+
str = $1
|
140
|
+
else
|
141
|
+
raise LoadError.new("No matching route found")
|
142
|
+
end
|
143
|
+
# match file route:
|
144
|
+
if str =~ /^(\/files\/.+)$/
|
145
|
+
return match.merge({ :file => $1 })
|
146
|
+
end
|
147
|
+
Beauty.routes.each do |entry|
|
66
148
|
k = entry[0]
|
67
149
|
v = entry[1]
|
68
|
-
if
|
150
|
+
if str =~ k
|
69
151
|
v.each do |sys,e|
|
70
|
-
match[sys] =
|
152
|
+
match[sys] =
|
153
|
+
(e =~ /^\$\d+$/ and str =~ k and eval e) ? (eval e) : e
|
71
154
|
end
|
72
155
|
break
|
73
156
|
end
|
74
157
|
end
|
158
|
+
raise LoadError.new("No matching route found") if match.keys.length <= 1
|
75
159
|
match
|
76
160
|
end
|
77
|
-
|
161
|
+
|
162
|
+
# Instance method
|
163
|
+
#
|
164
|
+
# Renders error stacktraces or errors back to the
|
165
|
+
# user
|
166
|
+
# [param code:] Error code integer
|
167
|
+
# [param type:] Exception type string
|
168
|
+
# [param bang:] Exception instance
|
169
|
+
# [returns:] Rack-compatible array
|
170
|
+
def render_error(code, type, bang)
|
171
|
+
if Beauty.config and Beauty.config[:production]
|
172
|
+
[code, {}, self.error_mapping(code)]
|
173
|
+
else
|
174
|
+
[200, {}, [
|
175
|
+
"<b>#{type}</b>",
|
176
|
+
"<em><pre>#{bang}</pre></em>",
|
177
|
+
"<pre>#{bang.backtrace.join("\n")}</pre>"
|
178
|
+
]]
|
179
|
+
end
|
180
|
+
end
|
181
|
+
|
182
|
+
# Instance method
|
183
|
+
#
|
184
|
+
# Maps error code integers to error strings
|
185
|
+
# [param code:] Error code integer
|
186
|
+
# [returns:] Error string
|
187
|
+
def error_mapping(code)
|
188
|
+
{
|
189
|
+
404 => "404 Page not found",
|
190
|
+
500 => "500 Internal error",
|
191
|
+
}[code]
|
192
|
+
end
|
193
|
+
|
78
194
|
end
|
79
|
-
|
80
195
|
end
|
data/lib/webink/controller.rb
CHANGED
@@ -12,7 +12,8 @@ module Ink
|
|
12
12
|
# class App < Ink::Controller
|
13
13
|
#
|
14
14
|
# def index
|
15
|
-
# redirect_to :controller => "my_app", :module => "feed",
|
15
|
+
# redirect_to :controller => "my_app", :module => "feed",
|
16
|
+
# :id => 29382374
|
16
17
|
# end
|
17
18
|
#
|
18
19
|
# def feed
|
@@ -29,9 +30,11 @@ module Ink
|
|
29
30
|
# end
|
30
31
|
#
|
31
32
|
# A controller named App should have the filename app.rb and be
|
32
|
-
# placed inside the project
|
33
|
+
# placed inside the project controllers folder. It can have
|
33
34
|
# instance methods that are usually refered to as modules.
|
34
35
|
# So a route should contain at least a :controller and a :module.
|
36
|
+
# Note that controller filenames are not camelized when they are
|
37
|
+
# being searched for by the dispatcher.
|
35
38
|
#
|
36
39
|
# In the sample above there are three modules, index redirects
|
37
40
|
# to feed, feed renders a template and partial renders a partial.
|
@@ -72,10 +75,11 @@ module Ink
|
|
72
75
|
# The routes being evaluated by the dispatcher are simple regular expressions.
|
73
76
|
# This example fits the controller from earlier.
|
74
77
|
#
|
75
|
-
# root = "/folder"
|
78
|
+
# Beauty.root = "/folder"
|
76
79
|
#
|
77
|
-
# routes = [
|
78
|
-
# [ /^\/([^\/]+)\/([^\/]+)(\/([0-9]+))?$/,
|
80
|
+
# Beauty.routes = [
|
81
|
+
# [ /^\/([^\/]+)\/([^\/]+)(\/([0-9]+))?$/,
|
82
|
+
# {:controller => "$1", :module => "$2", :id => "$4"} ],
|
79
83
|
# [ /^\/([^\/]+)\/?$/, {:controller => "$1", :module => "index"} ],
|
80
84
|
# [ /^\/?$/, {:controller => "app", :module => "index"} ],
|
81
85
|
# ]
|
@@ -94,7 +98,8 @@ module Ink
|
|
94
98
|
# will dynamically match the project path etc. (and is also using
|
95
99
|
# the root variable from the routes.rb)
|
96
100
|
#
|
97
|
-
# link_to "name", "controller", "module", "param1", "param2",
|
101
|
+
# link_to "name", "controller", "module", "param1", "param2",
|
102
|
+
# {:class => "h1", :id => "14"}
|
98
103
|
#
|
99
104
|
# The link above will produce this:
|
100
105
|
#
|
@@ -126,18 +131,18 @@ module Ink
|
|
126
131
|
# There is some basic support for it in webink, that will make certain
|
127
132
|
# bits easier. For more information have a look at the blog-demo.
|
128
133
|
#
|
129
|
-
# Each controller usually expects cookies to work
|
130
|
-
#
|
131
|
-
#
|
132
|
-
#
|
133
|
-
#
|
134
|
-
#
|
135
|
-
#
|
136
|
-
#
|
134
|
+
# Each controller usually expects cookies to work. Whenever cookies
|
135
|
+
# do not work, or you do not intend to use them in the first place,
|
136
|
+
# path_to and link_to watch out for the instance variables @session_key
|
137
|
+
# and @session_id which are added via GET to the path/hyperlink, that
|
138
|
+
# they construct. Therefore the tools should not be used for external
|
139
|
+
# linking. The dispatcher automatically filters the GET session_id when
|
140
|
+
# using POST and adds it to the cgi.params, so sessions can be used
|
141
|
+
# confortably.
|
137
142
|
#
|
138
|
-
# Per default, the @session_key should be "_session_id"
|
139
|
-
#
|
140
|
-
#
|
143
|
+
# Per default, the @session_key should be "_session_id", but the
|
144
|
+
# controller offers some freedom, in case you may want a different
|
145
|
+
# key name for some reason.
|
141
146
|
#
|
142
147
|
#
|
143
148
|
#
|
@@ -169,17 +174,18 @@ module Ink
|
|
169
174
|
template = File.open "./views/#{args[:template]}.html.erb", "r"
|
170
175
|
erb = ERB.new template.readlines * "\n"
|
171
176
|
template.close
|
172
|
-
|
173
|
-
erb.run self.getBinding(args[:locals])
|
177
|
+
[200, @params[:header], erb.result(self.getBinding(args[:locals]))]
|
174
178
|
elsif args[:partial]
|
175
|
-
template = File.open "./views/#{
|
179
|
+
template = File.open "./views/#{
|
180
|
+
(File.dirname(args[:partial]) != ".") ?
|
181
|
+
"#{File.dirname(args[:partial])}/" : ""
|
182
|
+
}_#{File.basename(args[:partial])}.html.erb", "r"
|
176
183
|
erb = ERB.new template.readlines * "\n"
|
177
184
|
template.close
|
178
185
|
if not args[:standalone]
|
179
|
-
erb.result
|
186
|
+
erb.result(self.getBinding(args[:locals]))
|
180
187
|
else
|
181
|
-
|
182
|
-
erb.run self.getBinding(args[:locals])
|
188
|
+
[200, @params[:header], erb.result(self.getBinding(args[:locals]))]
|
183
189
|
end
|
184
190
|
else
|
185
191
|
nil
|
@@ -201,8 +207,8 @@ module Ink
|
|
201
207
|
p[k] = v
|
202
208
|
end
|
203
209
|
if p[:controller] and p[:module]
|
204
|
-
controller =
|
205
|
-
|
210
|
+
controller = Ink::Controller.verify(p[:controller]).new(p)
|
211
|
+
controller.verify(p[:module]).call
|
206
212
|
else
|
207
213
|
nil
|
208
214
|
end
|
@@ -218,8 +224,10 @@ module Ink
|
|
218
224
|
# [param args:] Array of Strings and Hashes
|
219
225
|
# [returns:] Hyperlink
|
220
226
|
def link_to(*args)
|
221
|
-
|
222
|
-
|
227
|
+
if not args.instance_of? Array and args.length < 2
|
228
|
+
raise ArgumentError.new("Expects an array.")
|
229
|
+
end
|
230
|
+
href = "#{@params[:root]}/"
|
223
231
|
a = "<a "
|
224
232
|
name = args[0]
|
225
233
|
for i in 1...args.length
|
@@ -245,7 +253,7 @@ module Ink
|
|
245
253
|
# [param args:] Array of Strings or String
|
246
254
|
# [returns:] path
|
247
255
|
def path_to(*args)
|
248
|
-
href =
|
256
|
+
href = "#{@params[:root]}/"
|
249
257
|
|
250
258
|
if args.is_a? Array
|
251
259
|
for i in 0...args.length
|
@@ -275,14 +283,15 @@ module Ink
|
|
275
283
|
# [param controller:] Controller name string
|
276
284
|
# [returns:] class or nil
|
277
285
|
def self.verify(controller)
|
278
|
-
if not Module.const_defined?
|
279
|
-
if File.exists? "./controllers/#{controller}.rb"
|
286
|
+
if not Module.const_defined?(controller.capitalize)
|
287
|
+
if File.exists? "./controllers/#{controller}.rb" and
|
288
|
+
Module.const_get(controller.capitalize).is_a?(Class)
|
280
289
|
load "./controllers/#{controller}.rb"
|
281
290
|
else
|
282
291
|
raise NameError.new("Controller not found.")
|
283
292
|
end
|
284
293
|
end
|
285
|
-
|
294
|
+
Module.const_get(controller.capitalize)
|
286
295
|
end
|
287
296
|
|
288
297
|
# Instance method
|
data/lib/webink/database.rb
CHANGED
@@ -10,21 +10,19 @@ module Ink
|
|
10
10
|
#
|
11
11
|
# Sample config for MySQL:
|
12
12
|
# config = {
|
13
|
-
#
|
14
|
-
# "
|
15
|
-
#
|
16
|
-
#
|
17
|
-
#
|
18
|
-
#
|
19
|
-
# "db_server" => "localhost",
|
13
|
+
# :production => true,
|
14
|
+
# :db_type => "mysql",
|
15
|
+
# :db_user => "yourusername",
|
16
|
+
# :db_pass => "yourpassword",
|
17
|
+
# :db_database => "yourdatabase",
|
18
|
+
# :db_server => "localhost",
|
20
19
|
# }
|
21
20
|
#
|
22
21
|
# Sample config for SQLite3:
|
23
22
|
# config = {
|
24
|
-
#
|
25
|
-
# "
|
26
|
-
#
|
27
|
-
# "db_server" => "/full/path/to/database.sqlite",
|
23
|
+
# :production => true,
|
24
|
+
# :db_type => "sqlite3",
|
25
|
+
# :db_server => "/full/path/to/database.sqlite",
|
28
26
|
# }
|
29
27
|
#
|
30
28
|
# == Usage
|
@@ -109,12 +107,13 @@ module Ink
|
|
109
107
|
# possible.
|
110
108
|
# [param config:] Hash of config parameters
|
111
109
|
def initialize(config)
|
112
|
-
@type = config[
|
110
|
+
@type = config[:db_type]
|
113
111
|
if @type == "mysql"
|
114
|
-
@db = Mysql.real_connect(config[
|
112
|
+
@db = Mysql.real_connect(config[:db_server],config[:db_user],
|
113
|
+
config[:db_pass],config[:db_database])
|
115
114
|
@db.reconnect = true
|
116
115
|
elsif @type == "sqlite3"
|
117
|
-
@db = SQLite3::Database.new(config[
|
116
|
+
@db = SQLite3::Database.new(config[:db_server])
|
118
117
|
else
|
119
118
|
raise ArgumentError.new("Database undefined.")
|
120
119
|
end
|
@@ -140,7 +139,11 @@ module Ink
|
|
140
139
|
# Returns the Database instance or raises a Runtime Error
|
141
140
|
# [returns:] Database instance
|
142
141
|
def self.database
|
143
|
-
|
142
|
+
if @@database
|
143
|
+
@@database
|
144
|
+
else
|
145
|
+
raise RuntimeError.new("No Database found. Create one first")
|
146
|
+
end
|
144
147
|
end
|
145
148
|
|
146
149
|
# Instance method
|
@@ -158,7 +161,9 @@ module Ink
|
|
158
161
|
end
|
159
162
|
end
|
160
163
|
elsif @type == "sqlite3"
|
161
|
-
re = @db.query
|
164
|
+
re = @db.query <<QUERY
|
165
|
+
SELECT name FROM sqlite_master WHERE type='table' ORDER BY name;
|
166
|
+
QUERY
|
162
167
|
re.each do |row|
|
163
168
|
row.each do |t|
|
164
169
|
result.push t
|
@@ -273,7 +278,9 @@ module Ink
|
|
273
278
|
# [param class_name:] Defines the __table__ name or class
|
274
279
|
# [returns:] primary key or nil
|
275
280
|
def last_inserted_pk(class_name)
|
276
|
-
|
281
|
+
unless class_name.is_a?(Class)
|
282
|
+
class_name = Ink::Model.classname(class_name)
|
283
|
+
end
|
277
284
|
table_name = class_name.table_name
|
278
285
|
pk_name = class_name.primary_key
|
279
286
|
return if table_name.nil? or pk_name.nil?
|
@@ -302,7 +309,8 @@ module Ink
|
|
302
309
|
# [param class_name:] Defines the class name or class
|
303
310
|
# [param params:] Additional SQL syntax like WHERE conditions (optional)
|
304
311
|
def remove(class_name, params="")
|
305
|
-
table_name = (class_name.is_a? Class) ? class_name.table_name :
|
312
|
+
table_name = (class_name.is_a? Class) ? class_name.table_name :
|
313
|
+
Ink::Model.str_to_tablename(class_name)
|
306
314
|
return if table_name.nil?
|
307
315
|
self.query("DELETE FROM #{table_name} #{params};")
|
308
316
|
end
|
@@ -310,11 +318,14 @@ module Ink
|
|
310
318
|
# Instance method
|
311
319
|
#
|
312
320
|
# Retrieve class instances, that are loaded with the database result set.
|
313
|
-
# [param class_name:] Defines the class name or class which should be
|
321
|
+
# [param class_name:] Defines the class name or class which should be
|
322
|
+
# queried
|
314
323
|
# [param params:] Additional SQL syntax like WHERE conditions (optional)
|
315
324
|
# [returns:] Array of class_name instances from the SQL result set
|
316
325
|
def find(class_name, params="")
|
317
|
-
|
326
|
+
unless class_name.is_a?(Class)
|
327
|
+
class_name = Ink::Model.classname(class_name)
|
328
|
+
end
|
318
329
|
result = Array.new
|
319
330
|
table_name = class_name.table_name
|
320
331
|
return result if table_name.nil?
|
@@ -354,7 +365,11 @@ module Ink
|
|
354
365
|
union_class = ((class1.class_name <=> class2.class_name) < 0) ?
|
355
366
|
"#{tablename1}_#{tablename2}" :
|
356
367
|
"#{tablename2}_#{tablename1}"
|
357
|
-
re = self.query
|
368
|
+
re = self.query <<QUERY
|
369
|
+
SELECT #{tablename2}.* FROM #{union_class}, #{tablename2}
|
370
|
+
WHERE #{union_class}.#{fk1} = #{class1_id}
|
371
|
+
AND #{union_class}.#{fk2} = #{tablename2}.#{pk2} #{params};
|
372
|
+
QUERY
|
358
373
|
re.each do |entry|
|
359
374
|
instance = class2.new entry
|
360
375
|
result.push instance
|
@@ -384,10 +399,19 @@ module Ink
|
|
384
399
|
fk1 = class1.foreign_key
|
385
400
|
tablename1 = class1.table_name
|
386
401
|
tablename2 = class2.table_name
|
387
|
-
if ((class1.class_name <=> class2.class_name) < 0 and
|
388
|
-
|
402
|
+
if ((class1.class_name <=> class2.class_name) < 0 and
|
403
|
+
relationship == "one_one") or relationship == "one_many"
|
404
|
+
re = self.query <<QUERY
|
405
|
+
SELECT * FROM #{tablename2}
|
406
|
+
WHERE #{class2.primary_key}=(
|
407
|
+
SELECT #{class2.foreign_key} FROM #{tablename1}
|
408
|
+
WHERE #{class1.primary_key}=#{class1_id}
|
409
|
+
);
|
410
|
+
QUERY
|
389
411
|
else
|
390
|
-
re = self.query
|
412
|
+
re = self.query <<QUERY
|
413
|
+
SELECT * FROM #{tablename2} WHERE #{fk1} = #{class1_id} #{params};
|
414
|
+
QUERY
|
391
415
|
end
|
392
416
|
|
393
417
|
re.each do |entry|
|
@@ -400,7 +424,8 @@ module Ink
|
|
400
424
|
# Instance method
|
401
425
|
#
|
402
426
|
# Retrieve one class2 instance, that is related to the class1 instance with
|
403
|
-
# primary key class1_id. Only relevant for one_one and one_many
|
427
|
+
# primary key class1_id. Only relevant for one_one and one_many
|
428
|
+
# relationships
|
404
429
|
# [param class1:] Reference classname or class
|
405
430
|
# [param class1_id:] Primary key value of the reference classname
|
406
431
|
# [param class2:] Match classname or class
|
@@ -426,23 +451,42 @@ module Ink
|
|
426
451
|
# [param type:] relationship type
|
427
452
|
def delete_all_links(instance, link, type)
|
428
453
|
if type == "one_one"
|
429
|
-
firstclass =
|
430
|
-
|
431
|
-
|
454
|
+
firstclass =
|
455
|
+
((instance.class.name.downcase <=> link.name.downcase) < 0) ?
|
456
|
+
instance.class : link
|
457
|
+
secondclass =
|
458
|
+
((instance.class.name.downcase <=> link.name.downcase) < 0) ?
|
459
|
+
link : instance.class
|
460
|
+
key =
|
461
|
+
((instance.class.name.downcase <=> link.name.downcase) < 0) ?
|
462
|
+
instance.class.primary_key : instance.class.foreign_key
|
432
463
|
value = instance.method(instance.class.primary_key).call
|
433
|
-
@db.query
|
464
|
+
@db.query <<QUERY
|
465
|
+
UPDATE #{firstclass.table_name}
|
466
|
+
SET #{secondclass.foreign_key}=NULL
|
467
|
+
WHERE #{key}=#{value};
|
468
|
+
QUERY
|
434
469
|
elsif type == "one_many" or type == "many_one"
|
435
470
|
firstclass = (type == "one_many") ? instance.class : link
|
436
471
|
secondclass = (type == "one_many") ? link : instance.class
|
437
|
-
key = (type == "one_many") ? instance.class.primary_key :
|
472
|
+
key = (type == "one_many") ? instance.class.primary_key :
|
473
|
+
instance.class.foreign_key
|
438
474
|
value = instance.method(instance.class.primary_key).call
|
439
|
-
@db.query
|
475
|
+
@db.query <<QUERY
|
476
|
+
UPDATE #{firstclass.table_name}
|
477
|
+
SET #{secondclass.foreign_key}=NULL
|
478
|
+
WHERE #{key}=#{value};
|
479
|
+
QUERY
|
440
480
|
elsif type == "many_many"
|
441
481
|
tablename1 = instance.class.table_name
|
442
482
|
tablename2 = link.table_name
|
443
|
-
union_class =
|
483
|
+
union_class =
|
484
|
+
((instance.class.name.downcase <=> link.name.downcase) < 0) ?
|
485
|
+
"#{tablename1}_#{tablename2}" : "#{tablename2}_#{tablename1}"
|
444
486
|
value = instance.method(instance.class.primary_key).call
|
445
|
-
@db.query
|
487
|
+
@db.query <<QUERY
|
488
|
+
DELETE FROM #{union_class} WHERE #{instance.class.foreign_key}=#{value};
|
489
|
+
QUERY
|
446
490
|
end
|
447
491
|
end
|
448
492
|
|
@@ -452,10 +496,12 @@ module Ink
|
|
452
496
|
# link is the class of the related data, and type refers to the
|
453
497
|
# relationship type of the two. When one tries to insert an array
|
454
498
|
# for a x_one relationship, the last entry will be set.
|
455
|
-
# [param instance:] Instance of a class that refers to an existing
|
499
|
+
# [param instance:] Instance of a class that refers to an existing
|
500
|
+
# database entry
|
456
501
|
# [param link:] the related class (not a String, but class reference)
|
457
502
|
# [param type:] relationship type
|
458
|
-
# [param value:] relationship data that was set, either a primary key value,
|
503
|
+
# [param value:] relationship data that was set, either a primary key value,
|
504
|
+
# or an instance, or an array of both
|
459
505
|
def create_all_links(instance, link, type, value)
|
460
506
|
to_add = Array.new
|
461
507
|
if value.is_a? Array
|
@@ -482,7 +528,8 @@ module Ink
|
|
482
528
|
# The relationship between the two is defined by type. one_one
|
483
529
|
# relationships are placing an additional call to delete_all_links
|
484
530
|
# that will remove conflicts.
|
485
|
-
# [param instance:] Instance of a class that refers to an existing database
|
531
|
+
# [param instance:] Instance of a class that refers to an existing database
|
532
|
+
# entry
|
486
533
|
# [param link:] the related class (not a String, but class reference)
|
487
534
|
# [param type:] relationship type
|
488
535
|
# [param value:] primary key of the relationship, that is to be created
|
@@ -492,27 +539,49 @@ module Ink
|
|
492
539
|
re = self.find(link.name, "WHERE #{link.primary_key}=#{fk};").first
|
493
540
|
self.delete_all_links re, instance.class, type
|
494
541
|
end
|
495
|
-
firstclass =
|
496
|
-
|
497
|
-
|
542
|
+
firstclass =
|
543
|
+
((instance.class.name.downcase <=> link.name.downcase) < 0) ?
|
544
|
+
instance.class : link
|
545
|
+
secondclass =
|
546
|
+
((instance.class.name.downcase <=> link.name.downcase) < 0) ?
|
547
|
+
link : instance.class
|
548
|
+
key =
|
549
|
+
((instance.class.name.downcase <=> link.name.downcase) < 0) ?
|
550
|
+
instance.class.primary_key : link.primary_key
|
498
551
|
value = instance.method(instance.class.primary_key).call
|
499
|
-
fk_set =
|
500
|
-
|
501
|
-
|
552
|
+
fk_set =
|
553
|
+
((instance.class.name.downcase <=> link.name.downcase) < 0) ?
|
554
|
+
fk : value
|
555
|
+
value_set =
|
556
|
+
((instance.class.name.downcase <=> link.name.downcase) < 0) ?
|
557
|
+
value : fk
|
558
|
+
@db.query <<QUERY
|
559
|
+
UPDATE #{firstclass.table_name} SET #{secondclass.foreign_key}=#{fk}
|
560
|
+
WHERE #{key}=#{value};
|
561
|
+
QUERY
|
502
562
|
elsif type == "one_many" or type == "many_one"
|
503
563
|
firstclass = (type == "one_many") ? instance.class : link
|
504
564
|
secondclass = (type == "one_many") ? link : instance.class
|
505
|
-
key = (type == "one_many") ? instance.class.primary_key :
|
565
|
+
key = (type == "one_many") ? instance.class.primary_key :
|
566
|
+
link.primary_key
|
506
567
|
value = instance.method(instance.class.primary_key).call
|
507
568
|
fk_set = (type == "one_many") ? fk : value
|
508
569
|
value_set = (type == "one_many") ? value : fk
|
509
|
-
@db.query
|
570
|
+
@db.query <<QUERY
|
571
|
+
UPDATE #{firstclass.table_name} SET #{secondclass.foreign_key}=#{fk_set}
|
572
|
+
WHERE #{key}=#{value_set};
|
573
|
+
QUERY
|
510
574
|
elsif type == "many_many"
|
511
575
|
tablename1 = instance.class.table_name
|
512
576
|
tablename2 = link.table_name
|
513
|
-
union_class =
|
577
|
+
union_class =
|
578
|
+
((instance.class.name.downcase <=> link.name.downcase) < 0) ?
|
579
|
+
"#{tablename1}_#{tablename2}" : "#{tablename2}_#{tablename1}"
|
514
580
|
value = instance.method(instance.class.primary_key).call
|
515
|
-
@db.query
|
581
|
+
@db.query <<QUERY
|
582
|
+
INSERT INTO #{union_class}
|
583
|
+
(#{instance.class.foreign_key}, #{link.foreign_key}) VALUES (#{value}, #{fk});
|
584
|
+
QUERY
|
516
585
|
end
|
517
586
|
end
|
518
587
|
|
data/lib/webink/model.rb
CHANGED
@@ -139,15 +139,26 @@ module Ink
|
|
139
139
|
i = 0
|
140
140
|
self.class.fields.each do |k,v|
|
141
141
|
if data.is_a? Array
|
142
|
-
|
143
|
-
|
142
|
+
if data.length < self.class.fields.length - 1 or
|
143
|
+
data.length > self.class.fields.length
|
144
|
+
raise LoadError.new(<<ERR)
|
145
|
+
Model cannot be loaded, wrong number or arguments #{data.length} expected
|
146
|
+
#{self.class.fields.length} or #{self.class.fields.length - 1}
|
147
|
+
ERR
|
148
|
+
end
|
149
|
+
if self.class.primary_key != k or
|
150
|
+
data.length == self.class.fields.length
|
144
151
|
init_field k, data[i]
|
145
152
|
i += 1
|
146
153
|
else
|
147
154
|
init_field self.class.primary_key, nil
|
148
155
|
end
|
149
156
|
else
|
150
|
-
|
157
|
+
if not data.key?(k.to_s) and self.class.primary_key != k
|
158
|
+
raise LoadError.new(<<ERR)
|
159
|
+
Model cannot be loaded, argument missing: #{key}
|
160
|
+
ERR
|
161
|
+
end
|
151
162
|
init_field k, data[k.to_s]
|
152
163
|
end
|
153
164
|
end
|
@@ -188,7 +199,11 @@ module Ink
|
|
188
199
|
# [key:] String
|
189
200
|
# [value:] Object
|
190
201
|
def init_field(key, value)
|
191
|
-
|
202
|
+
if key.to_s.downcase == "pk"
|
203
|
+
raise NameError.new(<<ERR)
|
204
|
+
Model cannot use #{key} as field, it is blocked by primary key
|
205
|
+
ERR
|
206
|
+
end
|
192
207
|
entry = self.class.make_safe(value)
|
193
208
|
instance_variable_set("@#{key}", entry)
|
194
209
|
|
@@ -231,7 +246,11 @@ module Ink
|
|
231
246
|
# [key:] String
|
232
247
|
def init_foreign(key)
|
233
248
|
k_table = self.class.str_to_tablename(key)
|
234
|
-
|
249
|
+
if k_table == "pk"
|
250
|
+
raise NameError.new(<<ERR)
|
251
|
+
Model cannot use #{k_table} as foreign, it already exists
|
252
|
+
ERR
|
253
|
+
end
|
235
254
|
if not self.respond_to?(k_table)
|
236
255
|
instance_variable_set("@#{k_table}", nil)
|
237
256
|
self.class.send(:define_method, k_table) do
|
@@ -250,7 +269,11 @@ module Ink
|
|
250
269
|
# nil if you do not want to change them. Old references are
|
251
270
|
# automatically removed.
|
252
271
|
def save
|
253
|
-
|
272
|
+
if not self.class.respond_to?(:fields)
|
273
|
+
raise NotImplementedError.new(<<ERR)
|
274
|
+
Cannot save to Database without field definitions
|
275
|
+
ERR
|
276
|
+
end
|
254
277
|
string = Array.new
|
255
278
|
keystring = Array.new
|
256
279
|
valuestring = Array.new
|
@@ -259,21 +282,33 @@ module Ink
|
|
259
282
|
value = instance_variable_get "@#{k}"
|
260
283
|
value = "NULL" if value.nil?
|
261
284
|
if k != self.class.primary_key
|
262
|
-
string.push "`#{k}`=#{(value.is_a?(Numeric)) ? value :
|
285
|
+
string.push "`#{k}`=#{(value.is_a?(Numeric)) ? value :
|
286
|
+
"\'#{value}\'"}"
|
263
287
|
keystring.push "`#{k}`"
|
264
288
|
valuestring.push "#{(value.is_a?(Numeric)) ? value : "\'#{value}\'"}"
|
265
289
|
else
|
266
|
-
pkvalue = "WHERE `#{self.class.primary_key}`=#{
|
290
|
+
pkvalue = "WHERE `#{self.class.primary_key}`=#{
|
291
|
+
(value.is_a?(Numeric)) ? value : "\'#{value}\'"
|
292
|
+
}"
|
267
293
|
end
|
268
294
|
end
|
269
295
|
if pkvalue
|
270
296
|
response = Ink::Database.database.find self.class, pkvalue
|
271
297
|
if response.empty?
|
272
|
-
Ink::Database.database.query
|
298
|
+
Ink::Database.database.query <<QUERY
|
299
|
+
INSERT INTO #{self.class.table_name}
|
300
|
+
(#{keystring * ","}) VALUES
|
301
|
+
(#{valuestring * ","});
|
302
|
+
QUERY
|
273
303
|
pk = Ink::Database.database.last_inserted_pk(self.class)
|
274
|
-
|
304
|
+
if pk
|
305
|
+
instance_variable_set("@#{self.class.primary_key}",
|
306
|
+
pk.is_a?(Numeric) ? pk : "\'#{pk}\'")
|
307
|
+
end
|
275
308
|
else
|
276
|
-
Ink::Database.database.query
|
309
|
+
Ink::Database.database.query <<QUERY
|
310
|
+
UPDATE #{self.class.table_name} SET #{string * ","} #{pkvalue};
|
311
|
+
QUERY
|
277
312
|
end
|
278
313
|
end
|
279
314
|
|
@@ -281,8 +316,10 @@ module Ink
|
|
281
316
|
self.class.foreign.each do |k,v|
|
282
317
|
value = instance_variable_get "@#{self.class.str_to_tablename(k)}"
|
283
318
|
if value
|
284
|
-
Ink::Database.database.delete_all_links
|
285
|
-
|
319
|
+
Ink::Database.database.delete_all_links(self,
|
320
|
+
Ink::Model.classname(k), v)
|
321
|
+
Ink::Database.database.create_all_links(self,
|
322
|
+
Ink::Model.classname(k), v, value)
|
286
323
|
end
|
287
324
|
end
|
288
325
|
end
|
@@ -294,15 +331,24 @@ module Ink
|
|
294
331
|
# obsolete. Disregard from using the instance anymore.
|
295
332
|
# All links between models will be removed also.
|
296
333
|
def delete
|
297
|
-
|
334
|
+
if not self.class.respond_to? :fields
|
335
|
+
raise NotImplementedError.new(<<ERR)
|
336
|
+
Cannot delete from Database without field definitions
|
337
|
+
ERR
|
338
|
+
end
|
298
339
|
if self.class.respond_to? :foreign
|
299
340
|
self.class.foreign.each do |k,v|
|
300
|
-
Ink::Database.database.delete_all_links
|
341
|
+
Ink::Database.database.delete_all_links(self,
|
342
|
+
Ink::Model.classname(k), v)
|
301
343
|
end
|
302
344
|
end
|
303
345
|
|
304
346
|
pkvalue = instance_variable_get "@#{self.class.primary_key}"
|
305
|
-
Ink::Database.database.remove self.class.name,
|
347
|
+
Ink::Database.database.remove self.class.name, <<QUERY
|
348
|
+
WHERE `#{self.class.primary_key}`=#{
|
349
|
+
(pkvalue.is_a?(Numeric)) ? pkvalue : "\'#{pkvalue}\'"
|
350
|
+
}
|
351
|
+
QUERY
|
306
352
|
end
|
307
353
|
|
308
354
|
# Instance method
|
@@ -311,11 +357,15 @@ module Ink
|
|
311
357
|
# matching foreign accessor
|
312
358
|
# [param foreign_class:] Defines the foreign class name or class
|
313
359
|
def find_references(foreign_class)
|
314
|
-
c = (foreign_class.is_a? Class) ? foreign_class :
|
360
|
+
c = (foreign_class.is_a? Class) ? foreign_class :
|
361
|
+
Ink::Model.classname(foreign_class)
|
315
362
|
relationship = self.class.foreign[c.class_name]
|
316
363
|
if relationship
|
317
|
-
result_array = (relationship == "many_many") ?
|
318
|
-
|
364
|
+
result_array = (relationship == "many_many") ?
|
365
|
+
Ink::Database.database.find_union(self.class, self.pk, c) :
|
366
|
+
Ink::Database.database.find_references(self.class, self.pk, c)
|
367
|
+
instance_variable_set("@#{c.table_name}",
|
368
|
+
(relationship =~ /^one_/) ? result_array.first : result_array)
|
319
369
|
true
|
320
370
|
else
|
321
371
|
false
|
@@ -330,7 +380,11 @@ module Ink
|
|
330
380
|
# [returns:] Array of SQL statements
|
331
381
|
def self.create
|
332
382
|
result = Array.new
|
333
|
-
|
383
|
+
if not self.respond_to?(:fields)
|
384
|
+
raise NotImplementedError.new(<<ERR)
|
385
|
+
Cannot create a Database without field definitions
|
386
|
+
ERR
|
387
|
+
end
|
334
388
|
|
335
389
|
string = "CREATE TABLE #{self.table_name} ("
|
336
390
|
mfk = self.foreign_key
|
@@ -346,7 +400,12 @@ module Ink
|
|
346
400
|
tmp = self.foreign.map do |k,v|
|
347
401
|
f_class = Ink::Model::classname(k)
|
348
402
|
if v == "many_many" and (self.name <=> k) < 0
|
349
|
-
result.push
|
403
|
+
result.push <<QUERY
|
404
|
+
CREATE TABLE #{self.table_name}_#{Ink::Model::str_to_tablename(k)}
|
405
|
+
(#{Ink::Database.database.primary_key_autoincrement*" "},
|
406
|
+
`#{self.foreign_key}` #{self.foreign_key_type},
|
407
|
+
`#{f_class.foreign_key}` #{f_class.foreign_key_type});
|
408
|
+
QUERY
|
350
409
|
nil
|
351
410
|
end
|
352
411
|
if v == "one_many" or (v == "one_one" and (self.name <=> k) < 0)
|
@@ -387,9 +446,12 @@ module Ink
|
|
387
446
|
def self.str_to_classname(str)
|
388
447
|
res = []
|
389
448
|
str.scan(/((^|_)([a-z0-9]+))/) { |s|
|
390
|
-
|
449
|
+
if s.length > 0
|
450
|
+
res.push(s[2][0].upcase +
|
451
|
+
((s[2].length > 1) ? s[2][1,s[2].length] : ""))
|
452
|
+
end
|
391
453
|
}
|
392
|
-
|
454
|
+
Module.const_get(res.join).is_a?(Class) ? res.join : nil
|
393
455
|
end
|
394
456
|
|
395
457
|
# Class method
|
@@ -404,7 +466,7 @@ module Ink
|
|
404
466
|
str.scan(/([A-Z][a-z0-9]*)/) { |s|
|
405
467
|
res.push (res.length>0) ? "_" + s.join.downcase : s.join.downcase
|
406
468
|
}
|
407
|
-
|
469
|
+
Module.const_get(str).is_a?(Class) ? res.join : nil
|
408
470
|
end
|
409
471
|
|
410
472
|
# Class method
|
@@ -418,12 +480,15 @@ module Ink
|
|
418
480
|
res = []
|
419
481
|
if str[0] =~ /^[a-z]/
|
420
482
|
str.scan(/((^|_)([a-z0-9]+))/) { |s|
|
421
|
-
|
483
|
+
if s.length > 0
|
484
|
+
res.push(s[2][0].upcase +
|
485
|
+
((s[2].length > 1) ? s[2][1,s[2].length] : ""))
|
486
|
+
end
|
422
487
|
}
|
423
488
|
else
|
424
489
|
res.push str
|
425
490
|
end
|
426
|
-
|
491
|
+
Module.const_get(res.join).is_a?(Class) ? Module.const_get(res.join) : nil
|
427
492
|
end
|
428
493
|
|
429
494
|
# Class method
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: webink
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version:
|
4
|
+
version: 3.0.0
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,16 +9,16 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2013-06-
|
12
|
+
date: 2013-06-22 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
|
-
name:
|
15
|
+
name: rack
|
16
16
|
requirement: !ruby/object:Gem::Requirement
|
17
17
|
none: false
|
18
18
|
requirements:
|
19
19
|
- - ! '>='
|
20
20
|
- !ruby/object:Gem::Version
|
21
|
-
version:
|
21
|
+
version: 1.5.2
|
22
22
|
type: :runtime
|
23
23
|
prerelease: false
|
24
24
|
version_requirements: !ruby/object:Gem::Requirement
|
@@ -26,28 +26,12 @@ dependencies:
|
|
26
26
|
requirements:
|
27
27
|
- - ! '>='
|
28
28
|
- !ruby/object:Gem::Version
|
29
|
-
version:
|
30
|
-
- !ruby/object:Gem::Dependency
|
31
|
-
name: simple-mmap
|
32
|
-
requirement: !ruby/object:Gem::Requirement
|
33
|
-
none: false
|
34
|
-
requirements:
|
35
|
-
- - ! '>='
|
36
|
-
- !ruby/object:Gem::Version
|
37
|
-
version: 1.1.4
|
38
|
-
type: :runtime
|
39
|
-
prerelease: false
|
40
|
-
version_requirements: !ruby/object:Gem::Requirement
|
41
|
-
none: false
|
42
|
-
requirements:
|
43
|
-
- - ! '>='
|
44
|
-
- !ruby/object:Gem::Version
|
45
|
-
version: 1.1.4
|
29
|
+
version: 1.5.2
|
46
30
|
description:
|
47
31
|
email:
|
48
32
|
executables:
|
49
33
|
- webink_database
|
50
|
-
-
|
34
|
+
- webink_init
|
51
35
|
extensions: []
|
52
36
|
extra_rdoc_files: []
|
53
37
|
files:
|
@@ -57,7 +41,7 @@ files:
|
|
57
41
|
- lib/webink/database.rb
|
58
42
|
- lib/webink/model.rb
|
59
43
|
- bin/webink_database
|
60
|
-
- bin/
|
44
|
+
- bin/webink_init
|
61
45
|
- LICENSE.md
|
62
46
|
homepage: https://github.com/matthias-geier/WebInk
|
63
47
|
licenses: []
|
data/bin/rfcgi
DELETED
@@ -1,143 +0,0 @@
|
|
1
|
-
#!/usr/bin/env ruby
|
2
|
-
|
3
|
-
require "fcgi"
|
4
|
-
require "simple_mmap"
|
5
|
-
require "webink/beauty"
|
6
|
-
|
7
|
-
def getBinding(cgi,env,params)
|
8
|
-
return binding
|
9
|
-
end
|
10
|
-
def error(cgi, code)
|
11
|
-
puts cgi.header
|
12
|
-
puts cgi.header("nph" => true, "status" => code, "connection" => "close", "type" => "text/html")
|
13
|
-
end
|
14
|
-
|
15
|
-
script = nil
|
16
|
-
fhandle = nil
|
17
|
-
control = nil
|
18
|
-
pram = nil
|
19
|
-
is_production = nil
|
20
|
-
use_errors = nil
|
21
|
-
FCGI.each_cgi do |cgi|
|
22
|
-
is_production = ((cgi.env_table["INK_PRODUCTION"] and eval cgi.env_table["INK_PRODUCTION"]) or (ENV["INK_PRODUCTION"] and eval ENV["INK_PRODUCTION"])) ? true : false
|
23
|
-
use_errors = ((cgi.env_table["INK_ERRORS"] and eval cgi.env_table["INK_ERRORS"]) or (ENV["INK_ERRORS"] and eval ENV["INK_ERRORS"])) ? true : false
|
24
|
-
time = Time.now
|
25
|
-
script = cgi.env_table['SCRIPT_FILENAME']
|
26
|
-
begin
|
27
|
-
pram = Hash.new
|
28
|
-
CGI::parse(cgi.env_table['QUERY_STRING'].gsub(/\?/, "&")).each do |k,v|
|
29
|
-
if v.is_a? Array
|
30
|
-
if v.length == 0
|
31
|
-
pram[k] = nil
|
32
|
-
elsif v.length == 1
|
33
|
-
pram[k] = v[0]
|
34
|
-
else
|
35
|
-
pram[k] = v
|
36
|
-
end
|
37
|
-
else
|
38
|
-
pram[k] = v
|
39
|
-
end
|
40
|
-
end
|
41
|
-
control = pram['controller']
|
42
|
-
routes = Ink::Beauty.load_routes script
|
43
|
-
fhandle = SimpleMmap::MappedFile.new(routes)
|
44
|
-
Dir.chdir( File.dirname(routes) )
|
45
|
-
control = eval fhandle.read_window_data(0,fhandle.size), getBinding(cgi,cgi.env_table,control) if fhandle
|
46
|
-
fhandle.close
|
47
|
-
raise StandardError.new("Routes not matched.") if control.keys.length <= 1
|
48
|
-
|
49
|
-
control[:get] = pram
|
50
|
-
control[:config] = Ink::Beauty.load_config script
|
51
|
-
control[:time] = time
|
52
|
-
control[:cgi] = cgi
|
53
|
-
control[:env] = ENV
|
54
|
-
control[:is_production] = is_production
|
55
|
-
control[:use_errors] = use_errors
|
56
|
-
if cgi.env_table['REQUEST_METHOD'] == 'POST'
|
57
|
-
control[:post] = Hash.new
|
58
|
-
cgi.params.each do |k,v|
|
59
|
-
if v.is_a? Array
|
60
|
-
control[:post][k] = Array.new
|
61
|
-
v.each do |a|
|
62
|
-
control[:post][k].push((control[:config]["escape_post_data"]) ? CGI::escapeHTML(a) : a)
|
63
|
-
end
|
64
|
-
control[:post][k] = control[:post][k][0] if control[:post][k].length <= 1
|
65
|
-
else
|
66
|
-
control[:post][k] = (control[:config]["escape_post_data"]) ? CGI::escapeHTML(v) : v
|
67
|
-
end
|
68
|
-
end
|
69
|
-
pram.each do |k,v|
|
70
|
-
cgi.params[k] = v if not cgi.params.has_key? k
|
71
|
-
end
|
72
|
-
else
|
73
|
-
cgi.params = pram
|
74
|
-
end
|
75
|
-
|
76
|
-
script = Ink::Beauty.load_init script
|
77
|
-
fhandle = SimpleMmap::MappedFile.new(script)
|
78
|
-
Dir.chdir( File.dirname(script) )
|
79
|
-
eval fhandle.read_window_data(0,fhandle.size), getBinding(cgi,cgi.env_table,control) if fhandle
|
80
|
-
fhandle.close
|
81
|
-
|
82
|
-
rescue LoadError => bang
|
83
|
-
if is_production
|
84
|
-
puts cgi.header({"Location" => "/status-404.html"}) if use_errors
|
85
|
-
error cgi, "NOT_FOUND" if not use_errors
|
86
|
-
else
|
87
|
-
puts cgi.header
|
88
|
-
puts "<hr><b>LoadError:</b>", "<em><pre>", CGI::escapeHTML("#{bang}"), "</pre></em>\n", "<pre>", bang.backtrace.join("\n"), "</pre>"
|
89
|
-
end
|
90
|
-
|
91
|
-
rescue NotImplementedError => bang
|
92
|
-
if is_production
|
93
|
-
puts cgi.header({"Location" => "/status-500.html"}) if use_errors
|
94
|
-
error cgi, "SERVER_ERROR" if not use_errors
|
95
|
-
else
|
96
|
-
puts cgi.header
|
97
|
-
puts "<hr><b>NotImplementedError:</b>", "<em><pre>", CGI::escapeHTML("#{bang}"), "</pre></em>\n", "<pre>", bang.backtrace.join("\n"), "</pre>"
|
98
|
-
end
|
99
|
-
|
100
|
-
rescue ArgumentError => bang
|
101
|
-
if is_production
|
102
|
-
puts cgi.header({"Location" => "/status-500.html"}) if use_errors
|
103
|
-
error cgi, "SERVER_ERROR" if not use_errors
|
104
|
-
else
|
105
|
-
puts cgi.header
|
106
|
-
puts "<hr><b>ArgumentError:</b>", "<em><pre>", CGI::escapeHTML("#{bang}"), "</pre></em>\n", "<pre>", bang.backtrace.join("\n"), "</pre>"
|
107
|
-
end
|
108
|
-
|
109
|
-
rescue RuntimeError => bang
|
110
|
-
if is_production
|
111
|
-
puts cgi.header({"Location" => "/status-500.html"}) if use_errors
|
112
|
-
error cgi, "SERVER_ERROR" if not use_errors
|
113
|
-
else
|
114
|
-
puts cgi.header
|
115
|
-
puts "<hr><b>RuntimeError:</b>", "<em><pre>", CGI::escapeHTML("#{bang}"), "</pre></em>\n", "<pre>", bang.backtrace.join("\n"), "</pre>"
|
116
|
-
end
|
117
|
-
|
118
|
-
rescue NameError => bang
|
119
|
-
if is_production
|
120
|
-
puts cgi.header({"Location" => "/status-500.html"}) if use_errors
|
121
|
-
error cgi, "SERVER_ERROR" if not use_errors
|
122
|
-
else
|
123
|
-
puts cgi.header
|
124
|
-
puts "<hr><b>NameError:</b>", "<em><pre>", CGI::escapeHTML("#{bang}"), "</pre></em>\n", "<pre>", bang.backtrace.join("\n"), "</pre>"
|
125
|
-
end
|
126
|
-
|
127
|
-
rescue Exception, StandardError => bang
|
128
|
-
if is_production
|
129
|
-
puts cgi.header({"Location" => "/status-500.html"}) if use_errors
|
130
|
-
error cgi, "SERVER_ERROR" if not use_errors
|
131
|
-
else
|
132
|
-
puts cgi.header
|
133
|
-
puts "<hr><b>Exception:</b>", "<em><pre>", CGI::escapeHTML("#{bang}"), "</pre></em>\n", "<pre>", bang.backtrace.join("\n"), "</pre>"
|
134
|
-
end
|
135
|
-
end
|
136
|
-
|
137
|
-
script = nil
|
138
|
-
fhandle = nil
|
139
|
-
control = nil
|
140
|
-
pram = nil
|
141
|
-
GC.start
|
142
|
-
end
|
143
|
-
|