knjrbfw 0.0.29 → 0.0.30
Sign up to get free protection for your applications and to get access to all the features.
- data/VERSION +1 -1
- data/knjrbfw.gemspec +2 -1
- data/lib/knj/datet.rb +204 -6
- data/lib/knj/errors.rb +9 -0
- data/lib/knj/hash_methods.rb +10 -0
- data/lib/knj/http2.rb +62 -1
- data/lib/knj/knjdb/libknjdb.rb +99 -1
- data/lib/knj/knjdb/revision.rb +59 -34
- data/lib/knj/memory_analyzer.rb +13 -0
- data/lib/knj/os.rb +12 -0
- data/lib/knj/process.rb +5 -25
- data/lib/knj/process_meta.rb +13 -0
- data/lib/knj/threadsafe.rb +112 -25
- data/spec/threadsafe_spec.rb +57 -0
- metadata +15 -14
data/lib/knj/errors.rb
CHANGED
@@ -1,3 +1,4 @@
|
|
1
|
+
#This module contains various extra errors used by the other Knj-code.
|
1
2
|
module Knj::Errors
|
2
3
|
class Notice < StandardError; end
|
3
4
|
class NotFound < StandardError; end
|
@@ -6,6 +7,14 @@ module Knj::Errors
|
|
6
7
|
class NoAccess < StandardError; end
|
7
8
|
class Exists < StandardError; end
|
8
9
|
|
10
|
+
#Returns a string describing the given error. Possible arguments can be given if you want the returned string formatted as HTML.
|
11
|
+
#
|
12
|
+
#===Examples
|
13
|
+
# begin
|
14
|
+
# raise 'test'
|
15
|
+
# rescue => e
|
16
|
+
# print Knj::Errors.error_str(e, :html => true)
|
17
|
+
# end
|
9
18
|
def self.error_str(err, args = {})
|
10
19
|
if !err.is_a?(Exception) and err.class.message != "Java::JavaLang::LinkageError"
|
11
20
|
raise "Invalid object of class '#{err.class.name}' given."
|
data/lib/knj/hash_methods.rb
CHANGED
@@ -1,24 +1,34 @@
|
|
1
|
+
#A normal hash that uses 'method_missing' to be able to call keys by using methods. It is heavily used by Knj::Objects and have some pre-defined methods because of it to optimize performance.
|
2
|
+
#===Examples
|
3
|
+
# hm = Knj::Hash_methods(:test => "Test")
|
4
|
+
# print hm.test
|
1
5
|
class Knj::Hash_methods < Hash
|
6
|
+
#Spawns the object and takes a hash as argument.
|
2
7
|
def initialize(hash = {})
|
3
8
|
self.update(hash)
|
4
9
|
end
|
5
10
|
|
11
|
+
#Returns the db-key.
|
6
12
|
def db
|
7
13
|
return self[:db]
|
8
14
|
end
|
9
15
|
|
16
|
+
#Returns the ob-key.
|
10
17
|
def ob
|
11
18
|
return self[:ob]
|
12
19
|
end
|
13
20
|
|
21
|
+
#Returns the args-key.
|
14
22
|
def args
|
15
23
|
return self[:args]
|
16
24
|
end
|
17
25
|
|
26
|
+
#Returns the data-key.
|
18
27
|
def data
|
19
28
|
return self[:data]
|
20
29
|
end
|
21
30
|
|
31
|
+
#Proxies methods into the hash as keys.
|
22
32
|
def method_missing(method, *args)
|
23
33
|
method = method.to_sym
|
24
34
|
return self[method] if self.key?(method)
|
data/lib/knj/http2.rb
CHANGED
@@ -1,5 +1,16 @@
|
|
1
1
|
require "#{$knjpath}web"
|
2
2
|
|
3
|
+
#This class tries to emulate a browser in Ruby without any visual stuff. Remember cookies, keep sessions alive, reset connections according to keep-alive rules and more.
|
4
|
+
#===Examples
|
5
|
+
# Knj::Http2.new(:host => "www.somedomain.com", :port => 80, :ssl => false, :debug => false) do |http|
|
6
|
+
# res = http.get("index.rhtml?show=some_page")
|
7
|
+
# html = res.body
|
8
|
+
# print html
|
9
|
+
#
|
10
|
+
# res = res.post("index.rhtml?choice=login", {"username" => "John Doe", "password" => 123})
|
11
|
+
# print res.body
|
12
|
+
# print "#{res.headers}"
|
13
|
+
# end
|
3
14
|
class Knj::Http2
|
4
15
|
attr_reader :cookies, :args
|
5
16
|
|
@@ -44,6 +55,9 @@ class Knj::Http2
|
|
44
55
|
end
|
45
56
|
end
|
46
57
|
|
58
|
+
#Returns boolean based on the if the object is connected and the socket is working.
|
59
|
+
#===Examples
|
60
|
+
# print "Socket is working." if http.socket_working?
|
47
61
|
def socket_working?
|
48
62
|
return false if !@sock or @sock.closed?
|
49
63
|
|
@@ -58,6 +72,9 @@ class Knj::Http2
|
|
58
72
|
return true
|
59
73
|
end
|
60
74
|
|
75
|
+
#Destroys the object unsetting all variables and closing all sockets.
|
76
|
+
#===Examples
|
77
|
+
# http.destroy
|
61
78
|
def destroy
|
62
79
|
@args = nil
|
63
80
|
@cookies = nil
|
@@ -133,6 +150,10 @@ class Knj::Http2
|
|
133
150
|
end
|
134
151
|
end
|
135
152
|
|
153
|
+
#Returns a result-object based on the arguments.
|
154
|
+
#===Examples
|
155
|
+
# res = http.get("somepage.html")
|
156
|
+
# print res.body #=> <String>-object containing the HTML gotten.
|
136
157
|
def get(addr, args = {})
|
137
158
|
begin
|
138
159
|
@mutex.synchronize do
|
@@ -174,6 +195,10 @@ class Knj::Http2
|
|
174
195
|
@request_last = Time.now
|
175
196
|
end
|
176
197
|
|
198
|
+
#Returns the default headers for a request.
|
199
|
+
#===Examples
|
200
|
+
# headers_hash = http.default_headers
|
201
|
+
# print "#{headers_hash}"
|
177
202
|
def default_headers(args = {})
|
178
203
|
return args[:default_headers] if args[:default_headers]
|
179
204
|
|
@@ -213,6 +238,9 @@ class Knj::Http2
|
|
213
238
|
return praw
|
214
239
|
end
|
215
240
|
|
241
|
+
#Posts to a certain page.
|
242
|
+
#===Examples
|
243
|
+
# res = http.post("login.php", {"username" => "John Doe", "password" => 123)
|
216
244
|
def post(addr, pdata = {}, args = {})
|
217
245
|
begin
|
218
246
|
@mutex.synchronize do
|
@@ -231,6 +259,9 @@ class Knj::Http2
|
|
231
259
|
end
|
232
260
|
end
|
233
261
|
|
262
|
+
#Posts to a certain page using the multipart-method.
|
263
|
+
#===Examples
|
264
|
+
# res = http.post_multipart("upload.php", {"normal_value" => 123, "file" => Tempfile.new(?)})
|
234
265
|
def post_multipart(addr, pdata, args = {})
|
235
266
|
begin
|
236
267
|
@mutex.synchronize do
|
@@ -274,6 +305,7 @@ class Knj::Http2
|
|
274
305
|
end
|
275
306
|
end
|
276
307
|
|
308
|
+
#Returns a header-string which normally would be used for a request in the given state.
|
277
309
|
def header_str(headers_hash, args = {})
|
278
310
|
if @cookies.length > 0 and (!args.key?(:cookies) or args[:cookies])
|
279
311
|
cstr = ""
|
@@ -301,6 +333,9 @@ class Knj::Http2
|
|
301
333
|
args[:on_content].call(line) if args.key?(:on_content)
|
302
334
|
end
|
303
335
|
|
336
|
+
#Reads the response after posting headers and data.
|
337
|
+
#===Examples
|
338
|
+
# res = http.read_response
|
304
339
|
def read_response(args = {})
|
305
340
|
@mode = "headers"
|
306
341
|
@resp = Knj::Http2::Response.new
|
@@ -386,7 +421,10 @@ class Knj::Http2
|
|
386
421
|
end
|
387
422
|
end
|
388
423
|
|
389
|
-
|
424
|
+
#Parse a header-line and saves it on the object.
|
425
|
+
#===Examples
|
426
|
+
# http.parse_header("Content-Type: text/html\r\n")
|
427
|
+
def parse_header(line, args = {})
|
390
428
|
if match = line.match(/^(.+?):\s*(.+)#{@nl}$/)
|
391
429
|
key = match[1].to_s.downcase
|
392
430
|
|
@@ -436,6 +474,8 @@ class Knj::Http2
|
|
436
474
|
end
|
437
475
|
end
|
438
476
|
|
477
|
+
#Parses the body based on given headers and saves it to the result-object.
|
478
|
+
# http.parse_body(str)
|
439
479
|
def parse_body(line, args)
|
440
480
|
if @resp.args[:http_version] = "1.1"
|
441
481
|
return "break" if @length == 0
|
@@ -480,37 +520,58 @@ class Knj::Http2::Response
|
|
480
520
|
@args[:body] = "" if !@args.key?(:body)
|
481
521
|
end
|
482
522
|
|
523
|
+
#Returns headers given from the host for the result.
|
524
|
+
#===Examples
|
525
|
+
# headers_hash = res.headers
|
483
526
|
def headers
|
484
527
|
return @args[:headers]
|
485
528
|
end
|
486
529
|
|
530
|
+
#Returns a certain header by name or false if not found.
|
531
|
+
#===Examples
|
532
|
+
# val = res.header("content-type")
|
487
533
|
def header(key)
|
488
534
|
return false if !@args[:headers].key?(key)
|
489
535
|
return @args[:headers][key].first.to_s
|
490
536
|
end
|
491
537
|
|
492
538
|
#Returns true if a header of the given string exists.
|
539
|
+
#===Examples
|
540
|
+
# print "No content-type was given." if !http.header?("content-type")
|
493
541
|
def header?(key)
|
494
542
|
return true if @args[:headers].key?(key) and @args[:headers][key].first.to_s.length > 0
|
495
543
|
return false
|
496
544
|
end
|
497
545
|
|
546
|
+
#Returns the code of the result (200, 404, 500 etc).
|
547
|
+
#===Examples
|
548
|
+
# print "An internal error occurred." if res.code.to_i == 500
|
498
549
|
def code
|
499
550
|
return @args[:code]
|
500
551
|
end
|
501
552
|
|
553
|
+
#Returns the HTTP-version of the result.
|
554
|
+
#===Examples
|
555
|
+
# print "We are using HTTP 1.1 and should support keep-alive." if res.http_version.to_s == "1.1"
|
502
556
|
def http_version
|
503
557
|
return @args[:http_version]
|
504
558
|
end
|
505
559
|
|
560
|
+
#Returns the complete body of the result as a string.
|
561
|
+
#===Examples
|
562
|
+
# print "Looks like we caught the end of it as well?" if res.body.to_s.downcase.index("</html>") != nil
|
506
563
|
def body
|
507
564
|
return @args[:body]
|
508
565
|
end
|
509
566
|
|
567
|
+
#Returns the charset of the result.
|
510
568
|
def charset
|
511
569
|
return @args[:charset]
|
512
570
|
end
|
513
571
|
|
572
|
+
#Returns the content-type of the result as a string.
|
573
|
+
#===Examples
|
574
|
+
# print "This body can be printed - its just plain text!" if http.contenttype == "text/plain"
|
514
575
|
def contenttype
|
515
576
|
return @args[:contenttype]
|
516
577
|
end
|
data/lib/knj/knjdb/libknjdb.rb
CHANGED
@@ -1,3 +1,16 @@
|
|
1
|
+
#A wrapper of several possible database-types.
|
2
|
+
#
|
3
|
+
#===Examples
|
4
|
+
# db = Knj::Db.new(:type => "mysql", :subtype => "mysql2", :db => "mysql", :user => "user", :pass => "password")
|
5
|
+
# mysql_table = db.tables['mysql']
|
6
|
+
# name = mysql_table.name
|
7
|
+
# cols = mysql_table.columns
|
8
|
+
#
|
9
|
+
# db = Knj::Db.new(:type => "sqlite3", :path => "some_db.sqlite3")
|
10
|
+
#
|
11
|
+
# db.q("SELECT * FROM users") do |data|
|
12
|
+
# print data[:name]
|
13
|
+
# end
|
1
14
|
class Knj::Db
|
2
15
|
#Autoloader.
|
3
16
|
def self.const_missing(name)
|
@@ -44,6 +57,7 @@ class Knj::Db
|
|
44
57
|
self.connect
|
45
58
|
end
|
46
59
|
|
60
|
+
#Actually connects to the database. This is useually done automatically.
|
47
61
|
def connect
|
48
62
|
if @opts[:threadsafe]
|
49
63
|
@conns = Knj::Threadhandler.new
|
@@ -64,6 +78,9 @@ class Knj::Db
|
|
64
78
|
end
|
65
79
|
end
|
66
80
|
|
81
|
+
#Spawns a new driver (useally done automatically).
|
82
|
+
#===Examples
|
83
|
+
# driver_instance = db.spawn
|
67
84
|
def spawn
|
68
85
|
raise "No type given." if !@opts[:type]
|
69
86
|
|
@@ -83,6 +100,7 @@ class Knj::Db
|
|
83
100
|
return Kernel.const_get("KnjDB_#{@opts[:type]}").new(self)
|
84
101
|
end
|
85
102
|
|
103
|
+
#Registers a driver to the current thread.
|
86
104
|
def get_and_register_thread
|
87
105
|
raise "KnjDB-object is not in threadding mode." if !@conns
|
88
106
|
|
@@ -98,6 +116,7 @@ class Knj::Db
|
|
98
116
|
thread_cur[:knjdb][tid] = @conns.get_and_lock if !thread_cur[:knjdb][tid]
|
99
117
|
end
|
100
118
|
|
119
|
+
#Frees the current driver from the current thread.
|
101
120
|
def free_thread
|
102
121
|
thread_cur = Thread.current
|
103
122
|
tid = self.__id__
|
@@ -120,6 +139,7 @@ class Knj::Db
|
|
120
139
|
end
|
121
140
|
end
|
122
141
|
|
142
|
+
#The all driver-database-connections.
|
123
143
|
def close
|
124
144
|
@conn.close if @conn
|
125
145
|
@conns.destroy if @conns
|
@@ -128,10 +148,12 @@ class Knj::Db
|
|
128
148
|
@conns = nil
|
129
149
|
end
|
130
150
|
|
151
|
+
#Clones the current database-connection with possible extra arguments.
|
131
152
|
def clone_conn(args = {})
|
132
153
|
return Knj::Db.new(@opts.clone.merge(args))
|
133
154
|
end
|
134
155
|
|
156
|
+
#Copies the content of the current database to another instance of Knj::Db.
|
135
157
|
def copy_to(db, args = {})
|
136
158
|
data["tables"].each do |table|
|
137
159
|
table_args = nil
|
@@ -167,6 +189,10 @@ class Knj::Db
|
|
167
189
|
end
|
168
190
|
end
|
169
191
|
|
192
|
+
#Returns the data of this database in a hash.
|
193
|
+
#===Examples
|
194
|
+
# data = db.data
|
195
|
+
# tables_hash = data['tables']
|
170
196
|
def data
|
171
197
|
tables_ret = []
|
172
198
|
tables.list.each do |name, table|
|
@@ -178,6 +204,11 @@ class Knj::Db
|
|
178
204
|
}
|
179
205
|
end
|
180
206
|
|
207
|
+
#Simply inserts data into a table.
|
208
|
+
#
|
209
|
+
#===Examples
|
210
|
+
# db.insert(:users, {:name => "John", :lastname => "Doe"})
|
211
|
+
# id = db.insert(:users, {:name => "John", :lastname => "Doe"}, :return_id => true)
|
181
212
|
def insert(tablename, arr_insert, args = {})
|
182
213
|
self.conn_exec do |driver|
|
183
214
|
sql = "INSERT INTO #{driver.escape_table}#{tablename.to_s}#{driver.escape_table} ("
|
@@ -213,6 +244,13 @@ class Knj::Db
|
|
213
244
|
end
|
214
245
|
end
|
215
246
|
|
247
|
+
#Simply and optimal insert multiple rows into a table in a single query.
|
248
|
+
#
|
249
|
+
#===Examples
|
250
|
+
# db.insert_multi(:users, [
|
251
|
+
# {:name => "John", :lastname => "Doe"},
|
252
|
+
# {:name => "Kasper", :lastname => "Johansen"}
|
253
|
+
# ])
|
216
254
|
def insert_multi(tablename, arr_hashes)
|
217
255
|
self.conn_exec do |driver|
|
218
256
|
if driver.respond_to?(:insert_multi)
|
@@ -226,6 +264,10 @@ class Knj::Db
|
|
226
264
|
end
|
227
265
|
end
|
228
266
|
|
267
|
+
#Simple updates rows.
|
268
|
+
#
|
269
|
+
#===Examples
|
270
|
+
# db.update(:users, {:name => "John"}, {:lastname => "Doe"})
|
229
271
|
def update(tablename, arr_update, arr_terms = {})
|
230
272
|
return false if arr_update.empty?
|
231
273
|
|
@@ -286,6 +328,10 @@ class Knj::Db
|
|
286
328
|
return self.q(sql, &block)
|
287
329
|
end
|
288
330
|
|
331
|
+
#Returns a single row from a database.
|
332
|
+
#
|
333
|
+
#===Examples
|
334
|
+
# row = db.single(:users, {:lastname => "Doe"})
|
289
335
|
def single(tablename, arr_terms = nil, args = {})
|
290
336
|
args["limit"] = 1
|
291
337
|
|
@@ -299,6 +345,10 @@ class Knj::Db
|
|
299
345
|
|
300
346
|
alias :selectsingle :single
|
301
347
|
|
348
|
+
#Deletes rows from the database.
|
349
|
+
#
|
350
|
+
#===Examples
|
351
|
+
# db.delete(:users, {:lastname => "Doe"})
|
302
352
|
def delete(tablename, arr_terms)
|
303
353
|
self.conn_exec do |driver|
|
304
354
|
sql = "DELETE FROM #{driver.escape_table}#{tablename}#{driver.escape_table}"
|
@@ -313,6 +363,10 @@ class Knj::Db
|
|
313
363
|
return nil
|
314
364
|
end
|
315
365
|
|
366
|
+
#Internally used to generate SQL.
|
367
|
+
#
|
368
|
+
#===Examples
|
369
|
+
# sql = db.makeWhere({:lastname => "Doe"}, driver_obj)
|
316
370
|
def makeWhere(arr_terms, driver)
|
317
371
|
sql = ""
|
318
372
|
|
@@ -337,6 +391,11 @@ class Knj::Db
|
|
337
391
|
end
|
338
392
|
|
339
393
|
#Returns a driver-object based on the current thread and free driver-objects.
|
394
|
+
#
|
395
|
+
#===Examples
|
396
|
+
# db.conn_exec do |driver|
|
397
|
+
# str = driver.escape('something̈́')
|
398
|
+
# end
|
340
399
|
def conn_exec
|
341
400
|
if Thread.current[:knjdb]
|
342
401
|
tid = self.__id__
|
@@ -376,6 +435,12 @@ class Knj::Db
|
|
376
435
|
end
|
377
436
|
|
378
437
|
#Executes a query and returns the result.
|
438
|
+
#
|
439
|
+
#===Examples
|
440
|
+
# res = db.query('SELECT * FROM users')
|
441
|
+
# while data = res.fetch
|
442
|
+
# print data[:name]
|
443
|
+
# end
|
379
444
|
def query(string)
|
380
445
|
if @debug
|
381
446
|
print "SQL: #{string}\n"
|
@@ -392,6 +457,11 @@ class Knj::Db
|
|
392
457
|
end
|
393
458
|
|
394
459
|
#Execute an ubuffered query and returns the result.
|
460
|
+
#
|
461
|
+
#===Examples
|
462
|
+
# db.query_ubuf('SELECT * FROM users') do |data|
|
463
|
+
# print data[:name]
|
464
|
+
# end
|
395
465
|
def query_ubuf(string, &block)
|
396
466
|
ret = nil
|
397
467
|
|
@@ -407,7 +477,14 @@ class Knj::Db
|
|
407
477
|
return ret
|
408
478
|
end
|
409
479
|
|
410
|
-
#Clones the connection, executes
|
480
|
+
#Clones the connection, executes the given block and closes the connection again.
|
481
|
+
#
|
482
|
+
#===Examples
|
483
|
+
# db.cloned_conn do |conn|
|
484
|
+
# conn.q('SELCET * FROM users') do |data|
|
485
|
+
# print data[:name]
|
486
|
+
# end
|
487
|
+
# end
|
411
488
|
def cloned_conn(args = nil, &block)
|
412
489
|
clone_conn_args = {
|
413
490
|
:threadsafe => false
|
@@ -424,6 +501,11 @@ class Knj::Db
|
|
424
501
|
end
|
425
502
|
|
426
503
|
#Executes a query and returns the result. If a block is given the result is iterated over that block instead and it returns nil.
|
504
|
+
#
|
505
|
+
#===Examples
|
506
|
+
# db.q('SELECT * FROM users') do |data|
|
507
|
+
# print data[:name]
|
508
|
+
# end
|
427
509
|
def q(str, args = nil, &block)
|
428
510
|
#If the query should be executed in a new connection unbuffered.
|
429
511
|
if args
|
@@ -452,6 +534,9 @@ class Knj::Db
|
|
452
534
|
end
|
453
535
|
|
454
536
|
#Returns the last inserted ID.
|
537
|
+
#
|
538
|
+
#===Examples
|
539
|
+
# id = db.last_id
|
455
540
|
def lastID
|
456
541
|
self.conn_exec do |driver|
|
457
542
|
return driver.lastID
|
@@ -461,6 +546,9 @@ class Knj::Db
|
|
461
546
|
alias :last_id :lastID
|
462
547
|
|
463
548
|
#Escapes a string to be safe-to-use in a query-string.
|
549
|
+
#
|
550
|
+
#===Examples
|
551
|
+
# db.q("INSERT INTO users (name) VALUES ('#{db.esc('John')}')")
|
464
552
|
def escape(string)
|
465
553
|
self.conn_exec do |driver|
|
466
554
|
return driver.escape(string)
|
@@ -547,6 +635,10 @@ class Knj::Db
|
|
547
635
|
return @indexes
|
548
636
|
end
|
549
637
|
|
638
|
+
#Proxies the method to the driver.
|
639
|
+
#
|
640
|
+
#===Examples
|
641
|
+
# db.method_on_driver
|
550
642
|
def method_missing(method_name, *args)
|
551
643
|
self.conn_exec do |driver|
|
552
644
|
if driver.respond_to?(method_name.to_sym)
|
@@ -558,6 +650,12 @@ class Knj::Db
|
|
558
650
|
end
|
559
651
|
|
560
652
|
#Beings a transaction and commits when the block ends.
|
653
|
+
#
|
654
|
+
#===Examples
|
655
|
+
# db.transaction do |db|
|
656
|
+
# db.insert(:users, {:name => "John"})
|
657
|
+
# db.insert(:users, {:name => "Kasper"})
|
658
|
+
# end
|
561
659
|
def transaction
|
562
660
|
self.query("START TRANSACTION")
|
563
661
|
|