knjrbfw 0.0.39 → 0.0.40

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.
@@ -38,10 +38,6 @@ class Knj::Db
38
38
  @debug = @opts[:debug]
39
39
  end
40
40
 
41
- def col_table
42
- return "`"
43
- end
44
-
45
41
  def args
46
42
  return @opts
47
43
  end
@@ -118,6 +114,15 @@ class Knj::Db
118
114
  end
119
115
 
120
116
  thread_cur[:knjdb][tid] = @conns.get_and_lock if !thread_cur[:knjdb][tid]
117
+
118
+ #If block given then be ensure to free thread after yielding.
119
+ if block_given?
120
+ begin
121
+ yield
122
+ ensure
123
+ self.free_thread
124
+ end
125
+ end
121
126
  end
122
127
 
123
128
  #Frees the current driver from the current thread.
@@ -154,7 +159,19 @@ class Knj::Db
154
159
 
155
160
  #Clones the current database-connection with possible extra arguments.
156
161
  def clone_conn(args = {})
157
- return Knj::Db.new(@opts.clone.merge(args))
162
+ conn = Knj::Db.new(@opts.clone.merge(args))
163
+
164
+ if block_given?
165
+ begin
166
+ yield(conn)
167
+ ensure
168
+ conn.close
169
+ end
170
+
171
+ return nil
172
+ else
173
+ return conn
174
+ end
158
175
  end
159
176
 
160
177
  #Copies the content of the current database to another instance of Knj::Db.
@@ -213,6 +230,7 @@ class Knj::Db
213
230
  #===Examples
214
231
  # db.insert(:users, {:name => "John", :lastname => "Doe"})
215
232
  # id = db.insert(:users, {:name => "John", :lastname => "Doe"}, :return_id => true)
233
+ # sql = db.insert(:users, {:name => "John", :lastname => "Doe"}, :return_sql => true) #=> "INSERT INTO `users` (`name`, `lastname`) VALUES ('John', 'Doe')"
216
234
  def insert(tablename, arr_insert, args = nil)
217
235
  self.conn_exec do |driver|
218
236
  sql = "INSERT INTO #{driver.escape_table}#{tablename.to_s}#{driver.escape_table} ("
@@ -243,8 +261,10 @@ class Knj::Db
243
261
 
244
262
  sql << ")"
245
263
 
264
+ return sql if args and args[:return_sql]
246
265
  driver.query(sql)
247
266
  return driver.lastID if args and args[:return_id]
267
+ return nil
248
268
  end
249
269
  end
250
270
 
@@ -260,19 +280,19 @@ class Knj::Db
260
280
 
261
281
  self.conn_exec do |driver|
262
282
  if driver.respond_to?(:insert_multi)
263
- return driver.insert_multi(tablename, arr_hashes, args)
283
+ return [driver.insert_multi(tablename, arr_hashes, args)]
264
284
  else
265
- ids = [] if args and args[:return_id]
285
+ ret = [] if args and (args[:return_id] or args[:return_sql])
266
286
  arr_hashes.each do |hash|
267
- if ids
268
- ids << self.insert(tablename, hash, args)
287
+ if ret
288
+ ret << self.insert(tablename, hash, args)
269
289
  else
270
- self.insert(tablename, hash)
290
+ self.insert(tablename, hash, args)
271
291
  end
272
292
  end
273
293
 
274
- if ids
275
- return ids
294
+ if ret
295
+ return ret
276
296
  else
277
297
  return nil
278
298
  end
@@ -316,10 +336,30 @@ class Knj::Db
316
336
 
317
337
  #Makes a select from the given arguments: table-name, where-terms and other arguments as limits and orders. Also takes a block to avoid raping of memory.
318
338
  def select(tablename, arr_terms = nil, args = nil, &block)
339
+ #Set up vars.
319
340
  sql = ""
341
+ args_q = nil
342
+ select_sql = "*"
343
+
344
+ #Give 'cloned_ubuf' argument to 'q'-method.
345
+ if args and args[:cloned_ubuf]
346
+ args_q = {:cloned_ubuf => true}
347
+ end
348
+
349
+ #Set up IDQuery-stuff if that is given in arguments.
350
+ if args and args[:idquery]
351
+ if args[:idquery] == true
352
+ select_sql = "`id`"
353
+ col = :id
354
+ else
355
+ select_sql = "`#{self.esc_col(args[:idquery])}`"
356
+ col = args[:idquery]
357
+ end
358
+ end
320
359
 
360
+ #Get the driver and generate SQL.
321
361
  self.conn_exec do |driver|
322
- sql = "SELECT * FROM #{driver.escape_table}#{tablename.to_s}#{driver.escape_table}"
362
+ sql = "SELECT #{select_sql} FROM #{driver.escape_table}#{tablename.to_s}#{driver.escape_table}"
323
363
 
324
364
  if arr_terms != nil and !arr_terms.empty?
325
365
  sql << " WHERE #{self.makeWhere(arr_terms, driver)}"
@@ -327,24 +367,34 @@ class Knj::Db
327
367
 
328
368
  if args != nil
329
369
  if args["orderby"]
330
- sql << " ORDER BY "
331
- sql << args["orderby"]
370
+ sql << " ORDER BY #{args["orderby"]}"
332
371
  end
333
372
 
334
373
  if args["limit"]
335
- sql << " LIMIT " + args["limit"].to_s
374
+ sql << " LIMIT #{args["limit"]}"
336
375
  end
337
376
 
338
377
  if args["limit_from"] and args["limit_to"]
339
378
  raise "'limit_from' was not numeric: '#{args["limit_from"]}'." if !Knj::Php.is_numeric(args["limit_from"])
340
379
  raise "'limit_to' was not numeric: '#{args["limit_to"]}'." if !Knj::Php.is_numeric(args["limit_to"])
341
-
342
380
  sql << " LIMIT #{args["limit_from"]}, #{args["limit_to"]}"
343
381
  end
344
382
  end
345
383
  end
346
384
 
347
- return self.q(sql, &block)
385
+ #Do IDQuery if given in arguments.
386
+ if args and args[:idquery]
387
+ res = Knj::Db::Idquery.new(:db => self, :table => tablename, :query => sql, :col => col, &block)
388
+ else
389
+ res = self.q(sql, args_q, &block)
390
+ end
391
+
392
+ #Return result if a block wasnt given.
393
+ if block
394
+ return nil
395
+ else
396
+ return res
397
+ end
348
398
  end
349
399
 
350
400
  #Returns a single row from a database.
@@ -368,7 +418,7 @@ class Knj::Db
368
418
  #
369
419
  #===Examples
370
420
  # db.delete(:users, {:lastname => "Doe"})
371
- def delete(tablename, arr_terms)
421
+ def delete(tablename, arr_terms, args = nil)
372
422
  self.conn_exec do |driver|
373
423
  sql = "DELETE FROM #{driver.escape_table}#{tablename}#{driver.escape_table}"
374
424
 
@@ -376,6 +426,7 @@ class Knj::Db
376
426
  sql << " WHERE #{self.makeWhere(arr_terms, driver)}"
377
427
  end
378
428
 
429
+ return sql if args and args[:return_sql]
379
430
  driver.query(sql)
380
431
  end
381
432
 
@@ -543,6 +594,11 @@ class Knj::Db
543
594
  return ret
544
595
  end
545
596
 
597
+ #Yields a query-buffer and flushes at the end of the block given.
598
+ def q_buffer(&block)
599
+ Knj::Db::Query_buffer.new(:db => self, &block)
600
+ end
601
+
546
602
  #Returns the last inserted ID.
547
603
  #
548
604
  #===Examples
@@ -567,18 +623,21 @@ class Knj::Db
567
623
 
568
624
  alias :esc :escape
569
625
 
626
+ #Escapes the given string to be used as a column.
570
627
  def esc_col(str)
571
628
  self.conn_exec do |driver|
572
629
  return driver.esc_col(str)
573
630
  end
574
631
  end
575
632
 
633
+ #Escapes the given string to be used as a table.
576
634
  def esc_table(str)
577
635
  self.conn_exec do |driver|
578
636
  return driver.esc_table(str)
579
637
  end
580
638
  end
581
639
 
640
+ #Returns the sign for surrounding the string that should be used as a table.
582
641
  def enc_table
583
642
  if !@enc_table
584
643
  self.conn_exec do |driver|
@@ -589,6 +648,7 @@ class Knj::Db
589
648
  return @enc_table
590
649
  end
591
650
 
651
+ #Returns the sign for surrounding the string that should be used as a column.
592
652
  def enc_col
593
653
  if !@enc_col
594
654
  self.conn_exec do |driver|
@@ -663,6 +723,7 @@ class Knj::Db
663
723
  return @indexes
664
724
  end
665
725
 
726
+ #Returns the SQLSpec-module and spawns it if it isnt already spawned.
666
727
  def sqlspecs
667
728
  if !@sqlspecs
668
729
  require "#{File.dirname(__FILE__)}/drivers/#{@opts[:type]}/knjdb_#{@opts[:type]}_sqlspecs" if (!@opts.key?(:require) or @opts[:require])
@@ -674,6 +735,23 @@ class Knj::Db
674
735
  return @sqlspecs
675
736
  end
676
737
 
738
+ #Beings a transaction and commits when the block ends.
739
+ #
740
+ #===Examples
741
+ # db.transaction do |db|
742
+ # db.insert(:users, {:name => "John"})
743
+ # db.insert(:users, {:name => "Kasper"})
744
+ # end
745
+ def transaction(&block)
746
+ self.conn_exec do |driver|
747
+ driver.transaction(&block)
748
+ end
749
+ end
750
+
751
+ def col_table
752
+ return "`"
753
+ end
754
+
677
755
  #Proxies the method to the driver.
678
756
  #
679
757
  #===Examples
@@ -687,21 +765,4 @@ class Knj::Db
687
765
 
688
766
  raise "Method not found: #{method_name}"
689
767
  end
690
-
691
- #Beings a transaction and commits when the block ends.
692
- #
693
- #===Examples
694
- # db.transaction do |db|
695
- # db.insert(:users, {:name => "John"})
696
- # db.insert(:users, {:name => "Kasper"})
697
- # end
698
- def transaction
699
- self.query("START TRANSACTION")
700
-
701
- begin
702
- yield(self)
703
- ensure
704
- self.query("COMMIT")
705
- end
706
- end
707
768
  end
@@ -0,0 +1,43 @@
1
+ #This class buffers a lot of queries and flushes them out via transactions.
2
+ class Knj::Db::Query_buffer
3
+ #Constructor. Takes arguments to be used and a block.
4
+ def initialize(args)
5
+ @args = args
6
+ @queries = []
7
+ @debug = @args[:debug]
8
+
9
+ begin
10
+ yield(self)
11
+ ensure
12
+ self.flush if !@queries.empty?
13
+ end
14
+ end
15
+
16
+ #Adds a query to the buffer.
17
+ def query(str)
18
+ STDOUT.print "Adding to buffer: #{str}\n" if @debug
19
+ @queries << str
20
+ self.flush if @queries.length > 1000
21
+ return nil
22
+ end
23
+
24
+ #Delete as on a normal Knj::Db.
25
+ def delete(table, where)
26
+ self.query(@args[:db].delete(table, where, :return_sql => true))
27
+ return nil
28
+ end
29
+
30
+ #Flushes all queries out in a transaction.
31
+ def flush
32
+ return nil if @queries.empty?
33
+
34
+ @args[:db].transaction do
35
+ @queries.shift(1000).each do |str|
36
+ STDOUT.print "Executing via buffer: #{str}\n" if @debug
37
+ @args[:db].q(str)
38
+ end
39
+ end
40
+
41
+ return nil
42
+ end
43
+ end
data/lib/knj/locales.rb CHANGED
@@ -20,19 +20,15 @@ module Knj::Locales
20
20
  def self.localeconv
21
21
  f = Knj::Locales.lang["first"]
22
22
 
23
- dec = "."
24
- thousand = ","
25
- csv_delimiter = ","
26
-
27
23
  case f
28
- when "da", "es", "de", "sv"
24
+ when "da", "de", "es", "pl", "sv"
29
25
  dec = ","
30
26
  thousand = "."
31
27
  csv_delimiter = ";"
32
- when "en"
33
- #do nothing.
34
28
  else
35
- raise "Cant figure out numbers for language: #{f}."
29
+ dec = "."
30
+ thousand = ","
31
+ csv_delimiter = ","
36
32
  end
37
33
 
38
34
  return {
@@ -220,8 +220,8 @@ class Knj::Objects
220
220
  )
221
221
  sql_where << " AND #{table}`#{db.esc_col(key)}` IN (#{escape_sql})"
222
222
  end
223
- elsif val.is_a?(Hash) and val[:type] == "col"
224
- raise "No table was given for join." if !val.key?(:table)
223
+ elsif val.is_a?(Hash) and val[:type] == :col
224
+ raise "No table was given for join: '#{val}', key: '#{key}' on table #{table}." if !val.key?(:table)
225
225
 
226
226
  do_joins[val[:table].to_sym] = true
227
227
  sql_where << " AND #{table}`#{db.esc_col(key)}` = `#{db.esc_table(val[:table])}`.`#{db.esc_col(val[:name])}`"
data/lib/knj/process.rb CHANGED
@@ -1,6 +1,7 @@
1
1
  require "#{$knjpath}errors"
2
2
  require "#{$knjpath}thread"
3
3
 
4
+ #This class is able to control communicate with another Ruby-process also running Knj::Process.
4
5
  class Knj::Process
5
6
  attr_reader :blocks, :blocks_send
6
7
 
@@ -56,10 +57,12 @@ class Knj::Process
56
57
  end
57
58
  end
58
59
 
60
+ #Kills the listen-thread.
59
61
  def kill_listen
60
62
  @listen_thread.kill if @listen_thread
61
63
  end
62
64
 
65
+ #Joins the listen-thread and the error-thread.
63
66
  def join
64
67
  @listen_thread.join if @listen_thread
65
68
  sleep 0.5
@@ -76,6 +79,7 @@ class Knj::Process
76
79
  end
77
80
  end
78
81
 
82
+ #This method is called by listen on every loop.
79
83
  def listen_loop
80
84
  $stderr.print "listen-loop called.\n" if @debug
81
85
 
@@ -421,6 +425,8 @@ class Knj::Process
421
425
  end
422
426
 
423
427
  err.set_backtrace(bt)
428
+
429
+ $stderr.print Knj::Errors.error_str(err) if @debug
424
430
  raise err
425
431
  end
426
432
 
@@ -84,12 +84,14 @@ class Knj::Process_meta
84
84
  end
85
85
  end
86
86
 
87
+ #Finalizer for proxy-objects. Used for unsetting objects on the process-side.
87
88
  def proxy_finalizer(id)
88
89
  @finalize_mutex.synchronize do
89
90
  @finalize << id
90
91
  end
91
92
  end
92
93
 
94
+ #Flushes all finalized objects on the process-side.
93
95
  def check_finalizers
94
96
  return nil if @finalize.empty?
95
97
 
@@ -383,8 +385,8 @@ class Knj::Process_meta
383
385
  raise e if e.message.index("No such process") == nil
384
386
  end
385
387
 
386
- $stderr.print "Try to kill again...\n"
387
- retry
388
+ #$stderr.print "Try to kill again...\n"
389
+ #retry
388
390
  end
389
391
 
390
392
  @process = nil
@@ -1,3 +1,4 @@
1
+ #A small threadpool framework.
1
2
  class Knj::Threadpool
2
3
  def self.worker_data
3
4
  raise "This thread is not running via the threadpool." if !Thread.current[:knj_threadpool]
@@ -6,6 +7,9 @@ class Knj::Threadpool
6
7
 
7
8
  attr_reader :workers, :blocks, :mutex, :args, :events
8
9
 
10
+ #Constructor.
11
+ #===Examples
12
+ # tp = Knj::Threadpool.new(:threads => 5)
9
13
  def initialize(args = {})
10
14
  @args = args
11
15
  @args[:sleep] = 0.2 if !@args.key?(:sleep)
@@ -21,6 +25,7 @@ class Knj::Threadpool
21
25
  self.start
22
26
  end
23
27
 
28
+ #Starts the threadpool. This is automatically called from the constructor.
24
29
  def start
25
30
  @mutex.synchronize do
26
31
  if !@running
@@ -33,6 +38,7 @@ class Knj::Threadpool
33
38
  end
34
39
  end
35
40
 
41
+ #Stops the threadpool.
36
42
  def stop
37
43
  if @running
38
44
  @workers.each do |worker|
@@ -46,6 +52,7 @@ class Knj::Threadpool
46
52
  end
47
53
  end
48
54
 
55
+ #Runs the given block, waits for the result and returns the result.
49
56
  def run(*args, &block)
50
57
  raise "No block given." if !block_given?
51
58
  blockdata = {:block => block, :result => nil, :running => false, :runned => false, :args => args}
@@ -70,16 +77,18 @@ class Knj::Threadpool
70
77
  end
71
78
  end
72
79
 
80
+ #Runs the given block in the threadpool asynced. Returns a 'Knj::Threadpool::Asynced'-object that can be used to get the result and more.
73
81
  def run_async(*args, &block)
74
82
  raise "No block given." if !block_given?
75
83
 
76
84
  @mutex.synchronize do
77
85
  blockdata = {:block => block, :running => false, :runned => false, :args => args}
78
86
  @blocks << blockdata
79
- return blockdata
87
+ return Knj::Threadpool::Asynced.new(blockdata)
80
88
  end
81
89
  end
82
90
 
91
+ #Returns a new block to be runned if there is one. Otherwise false.
83
92
  def get_block
84
93
  return false if !@running
85
94
 
@@ -96,9 +105,11 @@ class Knj::Threadpool
96
105
  end
97
106
  end
98
107
 
108
+ #This is the threadpool worker-object. No need to spawn this manually.
99
109
  class Knj::Threadpool::Worker
100
110
  attr_reader :running
101
111
 
112
+ #Constructor. Should not be called manually.
102
113
  def initialize(args)
103
114
  @args = args
104
115
  @tp = @args[:threadpool]
@@ -112,6 +123,8 @@ class Knj::Threadpool::Worker
112
123
  def spawn_thread
113
124
  @thread = Knj::Thread.new do
114
125
  loop do
126
+ break if !@sleep or !@tp
127
+
115
128
  if !@blockdata
116
129
  sleep @sleep
117
130
  @blockdata = @tp.get_block if !@blockdata
@@ -128,47 +141,28 @@ class Knj::Threadpool::Worker
128
141
  }
129
142
 
130
143
  begin
131
- if @blockdata.key?(:result)
132
- begin
133
- @running = true
134
- res = @blockdata[:block].call(*@blockdata[:args])
135
- rescue Exception => e
136
- @mutex_tp.synchronize do
137
- @blockdata[:error] = e
138
- end
139
- ensure
140
- @running = false
141
-
142
- @mutex_tp.synchronize do
143
- @blockdata[:result] = res
144
- @blockdata[:runned] = true
145
- @blockdata[:running] = false
146
- end
147
-
148
- #Try to avoid slowdown of sleep by checking if there is a new block right away.
149
- @blockdata = @tp.get_block
150
- end
151
- else
152
- begin
153
- @blockdata[:block].call(*@blockdata[:args])
154
- rescue Exception => e
155
- if @tp.events.connected?(:on_error)
156
- @tp.events.call(:on_error, e)
157
- else
158
- STDOUT.print Knj::Errors.error_str(e)
159
- end
160
- ensure
161
- @mutex_tp.synchronize do
162
- @blockdata.clear if @blockdata
163
- @tp.blocks.delete(@blockdata)
164
- end
165
-
166
- #Try to avoid slowdown of sleep by checking if there is a new block right away.
167
- @blockdata = @tp.get_block
168
- end
144
+ @running = true
145
+ res = @blockdata[:block].call(*@blockdata[:args])
146
+ rescue => e
147
+ @mutex_tp.synchronize do
148
+ @blockdata[:error] = e
169
149
  end
170
150
  ensure
151
+ #Reset thread.
171
152
  Thread.current[:knj_threadpool] = nil
153
+
154
+ #Set running-status on worker.
155
+ @running = false
156
+
157
+ #Update block-data.
158
+ @mutex_tp.synchronize do
159
+ @blockdata[:result] = res if res
160
+ @blockdata[:runned] = true
161
+ @blockdata[:running] = false
162
+ end
163
+
164
+ #Try to avoid slowdown of sleep by checking if there is a new block right away.
165
+ @blockdata = @tp.get_block
172
166
  end
173
167
  end
174
168
  end
@@ -196,7 +190,7 @@ class Knj::Threadpool::Worker
196
190
  begin
197
191
  sleep 0.1
198
192
  raise "The worker was stopped during execution of the block."
199
- rescue Exception => e
193
+ rescue => e
200
194
  @blockdata[:error] = e
201
195
  end
202
196
  end
@@ -224,4 +218,54 @@ class Knj::Threadpool::Worker
224
218
  @thread.kill
225
219
  end
226
220
  end
221
+ end
222
+
223
+ #An object of this class will be returned when calling 'run_async'.
224
+ class Knj::Threadpool::Asynced
225
+ #Constructor. Should not be called manually.
226
+ def initialize(args)
227
+ @args = args
228
+ end
229
+
230
+ #Returns true if the asynced job is still running.
231
+ def running?
232
+ return true if @args[:running]
233
+ return false
234
+ end
235
+
236
+ #Returns true if the asynced job is done running.
237
+ def done?
238
+ return true if @args[:runned] or @args.empty? or @args[:error]
239
+ return false
240
+ end
241
+
242
+ #Returns true if the asynced job is still waiting to run.
243
+ def waiting?
244
+ return true if !@args.empty? and !@args[:running] and !@args[:runned]
245
+ return false
246
+ end
247
+
248
+ #Raises error if one has happened in the asynced job.
249
+ def error!
250
+ raise @args[:error] if @args.key?(:error)
251
+ end
252
+
253
+ #Sleeps until the asynced job is done. If an error occurred in the job, that error will be raised when calling the method.
254
+ def join
255
+ loop do
256
+ self.error!
257
+ break if self.done?
258
+ sleep 0.1
259
+ end
260
+
261
+ self.error!
262
+ end
263
+
264
+ #Returns the result of the job. If an error occurred in the job, that error will be raised when calling the method.
265
+ def result(args = nil)
266
+ self.join if args and args[:wait]
267
+ raise "Not done yet." unless self.done?
268
+ self.error!
269
+ return @args[:result]
270
+ end
227
271
  end
data/lib/knj/web.rb CHANGED
@@ -1,7 +1,7 @@
1
1
  class Knj::Web
2
2
  #Parses URI and returns hash with data.
3
3
  def self.parse_uri(str)
4
- uri_match = str.to_s.match(/^\/(.+?\..+?|)(\?(.+)|)$/)
4
+ uri_match = str.to_s.match(/^\/(.+?\..*?|)(\?(.*)|)$/)
5
5
  raise "Could not parse the URI: '#{str}'." if !uri_match
6
6
 
7
7
  return {