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.
@@ -1,43 +1,32 @@
1
+ #This class takes a database-schema from a hash and runs it against the database. It then checks that the database matches the given schema.
2
+ #
3
+ #===Examples
4
+ # db = Knj::Db.new(:type => "sqlite3", :path => "test_db.sqlite3")
5
+ # schema = {
6
+ # "tables" => {
7
+ # "columns" => [
8
+ # {"name" => "id", "type" => "int", "autoincr" => true, "primarykey" => true},
9
+ # {"name" => "name", "type" => "varchar"},
10
+ # {"name" => "lastname", "type" => "varchar"}
11
+ # ],
12
+ # "indexes" => [
13
+ # "name",
14
+ # {"name" => "lastname", "columns" => ["lastname"]}
15
+ # ]
16
+ # }
17
+ # }
18
+ #
19
+ # rev = Knj::Db::Revision.new
20
+ # rev.init_db("db" => db, "schema" => schema)
1
21
  class Knj::Db::Revision
2
22
  def initialize(args = {})
3
23
  @args = args
4
24
  end
5
25
 
6
- #This method checks if certain rows are present in a table based on a hash.
7
- def rows_init(args)
8
- db = args["db"]
9
- table = args["table"]
10
-
11
- raise "No db given." if !db
12
- raise "No table given." if !table
13
-
14
- args["rows"].each do |row_data|
15
- if row_data["find_by"]
16
- find_by = row_data["find_by"]
17
- elsif row_data["data"]
18
- find_by = row_data["data"]
19
- else
20
- raise "Could not figure out the find-by."
21
- end
22
-
23
- rows_found = 0
24
- args["db"].select(table.name, find_by) do |d_rows|
25
- rows_found += 1
26
-
27
- if Knj::ArrayExt.hash_diff?(Knj::ArrayExt.hash_sym(row_data["data"]), Knj::ArrayExt.hash_sym(d_rows), {"h2_to_h1" => false})
28
- print "Data was not right - updating row: #{JSON.generate(row_data["data"])}\n" if args["debug"]
29
- args["db"].update(table.name, row_data["data"], d_rows)
30
- end
31
- end
32
-
33
- if rows_found == 0
34
- print "Inserting row: #{JSON.generate(row_data["data"])}\n" if args["debug"]
35
- table.insert(row_data["data"])
36
- end
37
- end
38
- end
39
-
40
26
  #This initializes a database-structure and content based on a schema-hash.
27
+ #===Examples
28
+ # dbrev = Knj::Db::Revision.new
29
+ # dbrev.init_db("db" => db_obj, "schema" => schema_hash)
41
30
  def init_db(args)
42
31
  schema = args["schema"]
43
32
  db = args["db"]
@@ -283,4 +272,40 @@ class Knj::Db::Revision
283
272
  tables.clear
284
273
  tables = nil
285
274
  end
275
+
276
+ private
277
+
278
+ #This method checks if certain rows are present in a table based on a hash.
279
+ def rows_init(args)
280
+ db = args["db"]
281
+ table = args["table"]
282
+
283
+ raise "No db given." if !db
284
+ raise "No table given." if !table
285
+
286
+ args["rows"].each do |row_data|
287
+ if row_data["find_by"]
288
+ find_by = row_data["find_by"]
289
+ elsif row_data["data"]
290
+ find_by = row_data["data"]
291
+ else
292
+ raise "Could not figure out the find-by."
293
+ end
294
+
295
+ rows_found = 0
296
+ args["db"].select(table.name, find_by) do |d_rows|
297
+ rows_found += 1
298
+
299
+ if Knj::ArrayExt.hash_diff?(Knj::ArrayExt.hash_sym(row_data["data"]), Knj::ArrayExt.hash_sym(d_rows), {"h2_to_h1" => false})
300
+ print "Data was not right - updating row: #{JSON.generate(row_data["data"])}\n" if args["debug"]
301
+ args["db"].update(table.name, row_data["data"], d_rows)
302
+ end
303
+ end
304
+
305
+ if rows_found == 0
306
+ print "Inserting row: #{JSON.generate(row_data["data"])}\n" if args["debug"]
307
+ table.insert(row_data["data"])
308
+ end
309
+ end
310
+ end
286
311
  end
@@ -1,8 +1,14 @@
1
+ #This class contains methods to debug memory-leaks. It prints its collected information as HTML.
2
+ #===Examples
3
+ # ma = Knj::Memory_analyzer.new
4
+ # ma.write
1
5
  class Knj::Memory_analyzer
6
+ #Initialized various objects.
2
7
  def initialize
3
8
  @printed = {}
4
9
  end
5
10
 
11
+ #Writes all available memory-analyzer-information to the given IO.
6
12
  def write(to = $stdout)
7
13
  to.print "<div style=\"width: 600px;\">\n"
8
14
 
@@ -24,6 +30,7 @@ class Knj::Memory_analyzer
24
30
  to.print "</div>\n"
25
31
  end
26
32
 
33
+ #Writes information about the garbage-collector to the given IO as HTML.
27
34
  def garbage_collector(to = $stdout)
28
35
  to.print "<h1>Garbage collector</h1>\n"
29
36
 
@@ -36,6 +43,7 @@ class Knj::Memory_analyzer
36
43
  GC.start
37
44
  end
38
45
 
46
+ #Collects and writes out a lot of information about the spawned hashes as HTML to the given IO.
39
47
  def hashes(to = $stdout)
40
48
  hashes = {}
41
49
 
@@ -94,6 +102,7 @@ class Knj::Memory_analyzer
94
102
  to.write "</table>\n"
95
103
  end
96
104
 
105
+ #Collects and writes a lot of information about the spawned arrays as HTML to the given IO.
97
106
  def arrays(to = $stdout)
98
107
  arrays = {}
99
108
 
@@ -152,6 +161,7 @@ class Knj::Memory_analyzer
152
161
  to.write "</table>\n"
153
162
  end
154
163
 
164
+ #Collects a lot of information and writes a lot of info about the spawned global variables as HTML to the given IO.
155
165
  def global_vars(to = $stdout)
156
166
  to.print "<h1>Global variables</h1>\n"
157
167
  to.print "<table class=\"global_variables list\">\n"
@@ -195,6 +205,7 @@ class Knj::Memory_analyzer
195
205
  to.print "</table>\n"
196
206
  end
197
207
 
208
+ #Collects information about the spawned classes and writes it as HTML to the given IO.
198
209
  def constants(to = $stdout)
199
210
  to.print "<h1>Constants</h1>\n"
200
211
  to.print "<table class=\"memory_analyzer list\">\n"
@@ -219,6 +230,7 @@ class Knj::Memory_analyzer
219
230
  to.print "</table>\n"
220
231
  end
221
232
 
233
+ #Writes information about the given mod and submod to the given IO as HTML.
222
234
  def write_constant(to, mod, submod)
223
235
  submod_s = submod.to_s
224
236
 
@@ -278,6 +290,7 @@ class Knj::Memory_analyzer
278
290
  end
279
291
  end
280
292
 
293
+ #This class is used to calculate a guessed amount of memory the given object requires.
281
294
  class Knj::Memory_analyzer::Object_size_counter
282
295
  def initialize(obj)
283
296
  @checked = {}
@@ -1,4 +1,7 @@
1
1
  module Knj::Os
2
+ #Returns the path of the home-dir as a string.
3
+ #===Examples
4
+ # print "Looks like the current user uses Mozilla software?" if File.exists?("#{Knj::Os.homedir}/.mozilla")
2
5
  def self.homedir
3
6
  if ENV["USERPROFILE"]
4
7
  homedir = ENV["USERPROFILE"]
@@ -14,6 +17,8 @@ module Knj::Os
14
17
  end
15
18
 
16
19
  #This method was created to make up for the fact that Dir.tmpdir sometimes returns empty strings??
20
+ #===Examples
21
+ # tmp_db_path = "#{Knj::Os.tmpdir}/temp_db.sqlite3"
17
22
  def self.tmpdir
18
23
  require "tmpdir"
19
24
  tmpdir = Dir.tmpdir.to_s.strip
@@ -26,6 +31,9 @@ module Knj::Os
26
31
  raise "Could not figure out temp-dir."
27
32
  end
28
33
 
34
+ #This method returns the username of the current user.
35
+ #===Examples
36
+ # print "I can do what I want, I am root!" if Knj::Os.whoami == "root"
29
37
  def self.whoami
30
38
  if ENV["USERNAME"]
31
39
  whoami = ENV["USERNAME"]
@@ -40,6 +48,10 @@ module Knj::Os
40
48
  return whoami
41
49
  end
42
50
 
51
+ #Returns the operating system a string.
52
+ #===Examples
53
+ # print "Can I please move to another machine?" if Knj::Os.os == "windows"
54
+ # print "I like it better now." if Knj::Os.os == "linux"
43
55
  def self.os
44
56
  if ENV["OS"]
45
57
  teststring = ENV["OS"].to_s
@@ -182,21 +182,15 @@ class Knj::Process
182
182
  self.answer(id, "ok")
183
183
  when "send_block_buffer"
184
184
  Knj::Thread.new do
185
- mutex = Mutex.new #Protecting 'buffer_answers'-variable. Crashing JRuby...
186
185
  result_obj = Knj::Process::Resultobject.new(:process => self, :id => id, :obj => obj)
187
186
  block_res = nil
188
187
  buffer_done = false
189
188
 
190
189
  begin
191
- buffer_answers = []
192
-
190
+ buffer_answers = Knj::Threadsafe.std_array #JRuby needs the threadsafety.
193
191
  buffer_thread = Knj::Thread.new do
194
- dobreak = false
195
192
  loop do
196
- arr = nil
197
- mutex.synchronize do
198
- arr = buffer_answers.shift(200)
199
- end
193
+ arr = buffer_answers.shift(200)
200
194
 
201
195
  if !arr.empty?
202
196
  $stderr.print "Sending: #{arr.length} results.\n" if @debug
@@ -206,14 +200,7 @@ class Knj::Process
206
200
  sleep 0.05
207
201
  end
208
202
 
209
- if buffer_done
210
- mutex.synchronize do
211
- $stderr.print "Buffer-answers: #{buffer_answers.length}, #{buffer_answers.empty?}\n" if @debug
212
- dobreak = true if buffer_answers.empty? #since a break will not affect the real loop in Mutex#synchronize set this variable.
213
- end
214
-
215
- break if dobreak
216
- end
203
+ break if buffer_done and buffer_answers.empty?
217
204
  end
218
205
  end
219
206
 
@@ -222,12 +209,7 @@ class Knj::Process
222
209
  count = 0
223
210
  block_res = @on_rec.call(result_obj) do |answer_block|
224
211
  loop do
225
- len = nil
226
- mutex.synchronize do
227
- len = buffer_answers.length
228
- end
229
-
230
- if len > 1000
212
+ if buffer_answers.length > 1000
231
213
  $stderr.print "Buffer is more than 1000 - sleeping and tries again in 0.05 sec.\n" if @debug
232
214
  sleep 0.05
233
215
  else
@@ -236,9 +218,7 @@ class Knj::Process
236
218
  end
237
219
 
238
220
  count += 1
239
- mutex.synchronize do
240
- buffer_answers << answer_block
241
- end
221
+ buffer_answers << answer_block
242
222
 
243
223
  if count >= 100
244
224
  count = 0
@@ -1,9 +1,22 @@
1
1
  require "#{$knjpath}process"
2
2
  require "#{$knjpath}os"
3
3
 
4
+ #This class can spawn another Ruby-process and manipulate it to create objects, evaluate code, create proxy-objects and other stuff in that process.
5
+ #===Examples
6
+ # This will create another Ruby-process, spawn an integer with the value of 5, run upto(10) and return each block to the current block. In the end the subprocess is terminated.
7
+ # Knj::Process_meta.new do |subproc|
8
+ # proxy_int = subproc.new(:Integer, 5)
9
+ # proxy_int.upto(10) do |i|
10
+ # print "Number: #{i}\n"
11
+ # end
12
+ # end
4
13
  class Knj::Process_meta
5
14
  attr_reader :process, :pid
6
15
 
16
+ #===Examples
17
+ #Knj::Process_meta.new("id" => "my_subproc") #Will make this ID be shown in the command, so you can recocknize it from "ps aux".
18
+ #Knj::Process_meta.new("exec_path" => "ruby1.9.1") #If you want a certain Ruby-command to be used when starting the subprocess, instead of detecting the current one.
19
+ #Knj::Process_meta.new("debug" => true, "debug_err" => true) #Enables various debug-messages to be printed.
7
20
  def initialize(args = {})
8
21
  @args = args
9
22
  @objects = {}
@@ -1,33 +1,120 @@
1
- #Copied from Headius: https://github.com/headius/thread_safe. Not just bundeled because I would like to make changes later...
2
- #Minor modifications from Headius's original lib like submoduled, lower-case-safe and more...
1
+ require "monitor"
3
2
 
4
- if defined?(JRUBY_VERSION)
5
- require "jruby/synchronized"
3
+ #This module contains various tools to handle thread-safety easily and pretty.
4
+ module Knj::Threadsafe
5
+ #JRuby can corrupt an array in a threadded env. Use this method to only get a synchronized array when running JRuby and not having to write "if RUBY_ENGINE"-stuff.
6
+ def self.std_array
7
+ return Synced_array.new if RUBY_ENGINE == "jruby"
8
+ return []
9
+ end
6
10
 
7
- module Knj::Threadsafe
8
- # A thread-safe subclass of Array. This version locks
9
- # against the object itself for every method call,
10
- # ensuring only one thread can be reading or writing
11
- # at a time. This includes iteration methods like
12
- # #each.
13
- class Array < ::Array
14
- include JRuby::Synchronized
11
+ #Instances of this class proxies calls to a given-object by using a mutex or monitor.
12
+ #
13
+ #==== Examples
14
+ # threadsafe_array = Knj::Threadsafe::Proxy.new(:obj => [])
15
+ # threadsafe_array << 5
16
+ # ret = threadsafe_array[0]
17
+ #
18
+ # threadsafe_array = Knj::Threadsafe::Proxy.new(:obj => [], :monitor => true)
19
+ class Proxy
20
+ #Spawn needed vars.
21
+ def initialize(args)
22
+ if args[:monitor]
23
+ @mutex = Monitor.new
24
+ elsif args[:mutex]
25
+ @mutex = args[:mutex]
26
+ else
27
+ @mutex = Mutex.new
28
+ end
29
+
30
+ @obj = args[:obj]
15
31
  end
16
32
 
17
- # A thread-safe subclass of Hash. This version locks
18
- # against the object itself for every method call,
19
- # ensuring only one thread can be reading or writing
20
- # at a time. This includes iteration methods like
21
- # #each.
22
- class Hash < ::Hash
23
- include JRuby::Synchronized
33
+ #Proxies all calls to this object through the mutex.
34
+ def method_missing(method_name, *args, &block)
35
+ @mutex.synchronize do
36
+ @obj.__send__(method_name, *args, &block)
37
+ end
38
+ end
39
+ end
40
+
41
+ #This module can be included on a class to make all method-calls synchronized (by using monitor). Examples with array and hash are below.
42
+ #
43
+ #===Examples
44
+ # class MySyncedClass < SomeOtherClassThatNeedsToBeSynchronized
45
+ # include Knj::Threadsafe::Monitored
46
+ # end
47
+ module Monitored
48
+ def self.included(base)
49
+ Knj::Strings.const_get_full(base.to_s).class_eval do
50
+ self.instance_methods.each do |method_name|
51
+ #These two methods create warnings under JRuby.
52
+ if RUBY_ENGINE == "jruby"
53
+ next if method_name == :instance_exec or method_name == :instance_eval
54
+ end
55
+
56
+ new_method_name = "_ts_#{method_name}"
57
+ alias_method(new_method_name, method_name)
58
+
59
+ define_method method_name do |*args, &block|
60
+ #Need to use monitor, since the internal calls might have to run not-synchronized, and we have just overwritten the internal methods.
61
+ @_ts_mutex = Monitor.new if !@_ts_mutex
62
+ @_ts_mutex.synchronize do
63
+ return self._ts___send__(new_method_name, *args, &block)
64
+ end
65
+ end
66
+ end
67
+ end
68
+ end
69
+ end
70
+
71
+ #This module can be included on a class to make all method-calls synchronized (by using mutex). Examples with array and hash are below.
72
+ #
73
+ #===Examples
74
+ # class MySyncedClass < SomeOtherClassThatNeedsToBeSynchronized
75
+ # include Knj::Threadsafe::Mutexed
76
+ # end
77
+ module Mutexed
78
+ def self.included(base)
79
+ Knj::Strings.const_get_full(base.to_s).class_eval do
80
+ self.instance_methods.each do |method_name|
81
+ #These two methods create warnings under JRuby.
82
+ if RUBY_ENGINE == "jruby"
83
+ next if method_name == :instance_exec or method_name == :instance_eval
84
+ end
85
+
86
+ new_method_name = "_ts_#{method_name}"
87
+ alias_method(new_method_name, method_name)
88
+
89
+ define_method method_name do |*args, &block|
90
+ #Need to use monitor, since the internal calls might have to run not-synchronized, and we have just overwritten the internal methods.
91
+ @_ts_mutex = Mutex.new if !@_ts_mutex
92
+ @_ts_mutex.synchronize do
93
+ return self._ts___send__(new_method_name, *args, &block)
94
+ end
95
+ end
96
+ end
97
+ end
24
98
  end
25
99
  end
26
- else
27
- # Because MRI never runs code in parallel, the existing
28
- # non-thread-safe structures should usually work fine.
29
- module Knj::ThreadSafe
30
- Array = ::Array
31
- Hash = ::Hash
100
+
101
+ #Predefined synchronized array.
102
+ #
103
+ #===Examples
104
+ # arr = Knj::Threadsafe::Synced_array.new
105
+ # arr << 5
106
+ # ret = arr[0]
107
+ class Synced_array < ::Array
108
+ include Mutexed
109
+ end
110
+
111
+ #Predefined synchronized hash.
112
+ #
113
+ #===Examples
114
+ # h = Knj::Threadsafe::Synced_hash.new
115
+ # h['test'] = 'trala'
116
+ # ret = h['test']
117
+ class Synced_hash < ::Hash
118
+ include Mutexed
32
119
  end
33
120
  end
@@ -0,0 +1,57 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
2
+
3
+ describe "Threadsafe" do
4
+ it "should be able to spawn threadsafe proxy-objects" do
5
+ require "knjrbfw"
6
+
7
+ arr = Knj::Threadsafe::Proxy.new(:obj => {})
8
+
9
+ 0.upto(5) do |i|
10
+ arr[i] = i
11
+ end
12
+
13
+ Knj::Thread.new do
14
+ arr.each do |key, val|
15
+ res = key + val
16
+ sleep 0.1
17
+ end
18
+ end
19
+
20
+ 5.upto(10) do |i|
21
+ arr[i] = i
22
+ sleep 0.1
23
+ end
24
+ end
25
+
26
+ it "should be able to spawn special classes" do
27
+ require "knjrbfw"
28
+
29
+ #Create new synchronized hash.
30
+ arr = Knj::Threadsafe::Synced_hash.new
31
+
32
+ #Make sure we get the right results.
33
+ arr[1] = 2
34
+
35
+ res = arr[1]
36
+ raise "Expected 2 but got '#{res}'." if res != 2
37
+
38
+ #Set some values to test with.
39
+ 0.upto(5) do |i|
40
+ arr[i] = i
41
+ end
42
+
43
+ #Try to call through each through a thread and then also try to set new values, which normally would crash the hash.
44
+ Knj::Thread.new do
45
+ arr.each do |key, val|
46
+ res = key + val
47
+ sleep 0.1
48
+ end
49
+ end
50
+
51
+ #This should not crash it, since they should wait for each other.
52
+ 5.upto(10) do |i|
53
+ arr[i] = i
54
+ sleep 0.1
55
+ end
56
+ end
57
+ end