knjrbfw 0.0.29 → 0.0.30
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/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
|
|