knjrbfw 0.0.101 → 0.0.102

Sign up to get free protection for your applications and to get access to all the features.
data/lib/knj/knj.rb CHANGED
@@ -47,7 +47,18 @@ module Knj
47
47
 
48
48
  #Loads a gem by a given name. First tries to load the gem from a custom parent directory to enable loading of development-gems.
49
49
  def self.gem_require(gem_const, gem_name = nil)
50
+ #Support given an array for multiple gem-names in one call.
51
+ if gem_const.is_a?(Array) and gem_name == nil
52
+ gem_const.each do |gem_i|
53
+ self.gem_require(gem_i)
54
+ end
55
+
56
+ return nil
57
+ end
58
+
59
+ #Set correct names.
50
60
  gem_name = gem_const.to_s.downcase.strip if !gem_name
61
+ gem_const = "#{gem_const.to_s[0].upcase}#{gem_const.to_s[1, gem_name.length]}"
51
62
 
52
63
  #Return false if the constant is already loaded.
53
64
  return false if ::Kernel.const_defined?(gem_const)
@@ -68,6 +79,7 @@ module Knj
68
79
 
69
80
  #Custom-path could not be loaded - load gem normally.
70
81
  if !found_custom
82
+ require "rubygems"
71
83
  require gem_name
72
84
  end
73
85
 
@@ -161,18 +161,17 @@ class KnjDB_mysql
161
161
  end
162
162
  end
163
163
  rescue => e
164
- if tries < 3
164
+ if tries <= 3
165
165
  if e.message == "MySQL server has gone away" or e.message == "closed MySQL connection" or e.message == "Can't connect to local MySQL server through socket"
166
166
  sleep 0.5
167
167
  self.reconnect
168
168
  retry
169
- elsif e.to_s.index("No operations allowed after connection closed") != nil or e.message == "This connection is still waiting for a result, try again once you have the result"
169
+ elsif e.message.include?("No operations allowed after connection closed") or e.message == "This connection is still waiting for a result, try again once you have the result" or e.message == "Lock wait timeout exceeded; try restarting transaction"
170
170
  self.reconnect
171
171
  retry
172
172
  end
173
173
  end
174
174
 
175
- #print str
176
175
  raise e
177
176
  end
178
177
  end
@@ -584,13 +583,13 @@ class KnjDB_java_mysql_result
584
583
 
585
584
  if @as_hash
586
585
  ret = {}
587
- 1.upto(@keys.length) do |count|
588
- ret[@keys[count - 1]] = @result.string(count)
586
+ 1.upto(@count) do |count|
587
+ ret[@keys[count - 1]] = @result.object(count)
589
588
  end
590
589
  else
591
590
  ret = []
592
591
  1.upto(@count) do |count|
593
- ret << @result.string(count)
592
+ ret << @result.object(count)
594
593
  end
595
594
  end
596
595
 
@@ -26,6 +26,7 @@ class KnjDB_mysql::Columns
26
26
  sql << " COMMENT '#{@args[:db].escape(data["comment"])}'" if data.key?("comment")
27
27
  sql << " AFTER `#{@args[:db].esc_col(data["after"])}`" if data["after"] and !data["first"]
28
28
  sql << " FIRST" if data["first"]
29
+ sql << " STORAGE #{data["storage"].to_s.upcase}" if data["storage"]
29
30
 
30
31
  return sql
31
32
  end
@@ -56,6 +56,12 @@ class KnjDB_mysql::Indexes::Index
56
56
  end
57
57
  end
58
58
 
59
+ #Returns true if the index is a primary-index.
60
+ def primary?
61
+ return true if @args[:data][:Index_type] == "BTREE"
62
+ return false
63
+ end
64
+
59
65
  #Inspect crashes if this is not present? - knj.
60
66
  def to_s
61
67
  return "#<#{self.class.name}>"
@@ -1,3 +1,5 @@
1
+ require "monitor"
2
+
1
3
  #This class handels various MySQL-table-specific behaviour.
2
4
  class KnjDB_mysql::Tables
3
5
  attr_reader :db, :list
@@ -7,7 +9,7 @@ class KnjDB_mysql::Tables
7
9
  @args = args
8
10
  @db = @args[:db]
9
11
  @subtype = @db.opts[:subtype]
10
- @list_mutex = Mutex.new
12
+ @list_mutex = Monitor.new
11
13
  @list = Wref_map.new
12
14
  @list_should_be_reloaded = true
13
15
  end
@@ -84,7 +86,7 @@ class KnjDB_mysql::Tables
84
86
  sql << @db.cols.data_sql(col_data)
85
87
  end
86
88
 
87
- if data["indexes"]
89
+ if data["indexes"] and !data["indexes"].empty?
88
90
  sql << ", "
89
91
  sql << KnjDB_mysql::Tables::Table.create_indexes(data["indexes"], {
90
92
  :db => @db,
@@ -353,4 +355,89 @@ class KnjDB_mysql::Tables::Table
353
355
  def insert(data)
354
356
  @db.insert(self.name, data)
355
357
  end
358
+
359
+ #Returns the current engine of the table.
360
+ def engine
361
+ return @data[:Engine]
362
+ end
363
+
364
+ def clone(newname, args = {})
365
+ raise "Invalid name." if newname.to_s.strip.empty?
366
+
367
+ sql = "CREATE TABLE `#{@db.esc_table(newname)}` ("
368
+ first = true
369
+ pkey_found = false
370
+ pkeys = []
371
+
372
+ self.columns do |col|
373
+ sql << ", " if !first
374
+ first = false if first
375
+
376
+ col_data = col.data
377
+ pkey_found = true if !pkey_found and col_data["primarykey"] and args[:force_single_pkey]
378
+
379
+ if args[:no_pkey] or (pkey_found and col_data["primarykey"] and args[:force_single_pkey])
380
+ col_data["primarykey"] = false
381
+ end
382
+
383
+ if col_data["primarykey"]
384
+ pkeys << col_data["name"]
385
+ col_data.delete("primarykey")
386
+ end
387
+
388
+ if args[:all_cols_storage]
389
+ col_data["storage"] = args[:all_cols_storage]
390
+ end
391
+
392
+ sql << @db.cols.data_sql(col_data)
393
+ end
394
+
395
+ if !pkeys.empty?
396
+ sql << ", PRIMARY KEY ("
397
+
398
+ first = true
399
+ pkeys.each do |pkey|
400
+ sql << ", " if !first
401
+ first = false if first
402
+ sql << "`#{@db.esc_col(pkey)}`"
403
+ end
404
+
405
+ sql << ")"
406
+ end
407
+
408
+ sql << ")"
409
+ sql << " TABLESPACE #{args[:tablespace]}" if args[:tablespace]
410
+ sql << " ENGINE=#{args[:engine]}" if args[:engine]
411
+ sql << ";"
412
+
413
+ puts sql
414
+
415
+ #Create table.
416
+ @db.query(sql)
417
+
418
+
419
+ #Insert data of previous data in a single query.
420
+ @db.query("INSERT INTO `#{newname}` SELECT * FROM `#{self.name}`")
421
+
422
+
423
+ #Create indexes.
424
+ new_table = @db.tables[newname]
425
+ indexes_list = []
426
+ self.indexes do |index|
427
+ indexes_list << index.data if !index.primary?
428
+ end
429
+
430
+ new_table.create_indexes(indexes_list)
431
+
432
+
433
+ #Return new table.
434
+ return new_table
435
+ end
436
+
437
+ #Changes the engine for a table.
438
+ def engine=(newengine)
439
+ raise "Invalid engine: '#{newengine}'." if !newengine.to_s.match(/^[A-z]+$/)
440
+ @db.query("ALTER TABLE `#{@db.esc_table(self.name)}` ENGINE = #{newengine}") if self.engine.to_s != newengine.to_s
441
+ @data[:Engine] = newengine
442
+ end
356
443
  end
@@ -1,8 +1,4 @@
1
- if !Kernel.const_defined?(:Wref) or !Kernel.const_defined?(:Datet)
2
- require "rubygems"
3
- require "wref" if !Kernel.const_defined?(:Wref)
4
- require "datet" if !Kernel.const_defined?(:Datet)
5
- end
1
+ Knj.gem_require([:wref, :datet])
6
2
 
7
3
  #A wrapper of several possible database-types.
8
4
  #
@@ -11,11 +11,13 @@ class Knj::Db::Query_buffer
11
11
 
12
12
  STDOUT.puts "Query buffer started." if @debug
13
13
 
14
- begin
15
- yield(self)
16
- ensure
17
- self.flush
18
- end
14
+ if block_given?
15
+ begin
16
+ yield(self)
17
+ ensure
18
+ self.flush
19
+ end
20
+ end
19
21
  end
20
22
 
21
23
  #Adds a query to the buffer.
@@ -27,6 +27,9 @@ class Knj::Memory_analyzer
27
27
  self.global_vars(to)
28
28
  GC.start
29
29
 
30
+ self.procs(to)
31
+ GC.start
32
+
30
33
  to.print "</div>\n"
31
34
  end
32
35
 
@@ -35,9 +38,9 @@ class Knj::Memory_analyzer
35
38
  to.print "<h1>Garbage collector</h1>\n"
36
39
 
37
40
  if GC.enable
38
- to.print "<div>Garbage collector was not enabled! But it is again now!</div>\n"
41
+ to.print "<div>Garbage collector is not enabled! But it is again now!</div>\n"
39
42
  else
40
- to.print "<div>Garbage collector was already enabled.</div>\n"
43
+ to.print "<div>Garbage collector is enabled.</div>\n"
41
44
  end
42
45
 
43
46
  GC.start
@@ -288,6 +291,44 @@ class Knj::Memory_analyzer
288
291
  end
289
292
  end
290
293
  end
294
+
295
+ #Writes information about which files (with line numbers) has spawned the most alive procs. This can give hints about memory leaks.
296
+ def procs(to = $stdout)
297
+ procs = {}
298
+
299
+ ObjectSpace.each_object(Proc) do |blk|
300
+ sloc_arr = blk.source_location
301
+ next if !sloc_arr
302
+
303
+ sloc = "#{sloc_arr[0]}:#{sloc_arr[1]}"
304
+ procs[sloc] = 0 if !procs.key?(sloc)
305
+ procs[sloc] += 1
306
+ end
307
+
308
+ procs = Knj::ArrayExt.hash_sort(procs) do |ele1, ele2|
309
+ ele2[1] <=> ele1[1]
310
+ end
311
+
312
+ to.puts "<h1>Alive procs by source</h1>"
313
+ to.puts "<table style=\"width: 600px;\">"
314
+ to.puts "\t<tbody>"
315
+
316
+ procs.each do |sloc, count|
317
+ next if count <= 2
318
+
319
+ to.puts "\t\t<tr>"
320
+ to.puts "\t\t\t<td>"
321
+ to.puts "\t\t\t\t#{sloc}"
322
+ to.puts "\t\t\t</td>"
323
+ to.puts "\t\t\t<td style=\"text-align: right;\">"
324
+ to.puts "\t\t\t\t#{_hb.num(count, 0)}"
325
+ to.puts "\t\t\t</td>"
326
+ to.puts "\t\t</tr>"
327
+ end
328
+
329
+ to.puts "\t</tbody>"
330
+ to.puts "</table>"
331
+ end
291
332
  end
292
333
 
293
334
  #This class is used to calculate a guessed amount of memory the given object requires.
data/lib/knj/objects.rb CHANGED
@@ -335,7 +335,7 @@ class Knj::Objects
335
335
  elsif data.is_a?(Hash) and data.key?(@args[:col_id].to_s)
336
336
  id = data[@args[:col_id].to_s].to_i
337
337
  elsif
338
- raise ArgumentError, "Unknown data: '#{data.class.to_s}'."
338
+ raise ArgumentError, "Unknown data for class '#{classname}': '#{data.class.to_s}' (#{data})."
339
339
  end
340
340
 
341
341
  if @objects.key?(classname)
@@ -944,7 +944,7 @@ class Knj::Objects
944
944
  end
945
945
  end
946
946
 
947
- #Erases the whole cache and regenerates is from ObjectSpace if not running weak-link-caching. If running weaklink-caching then only removes the dead links.
947
+ #Erases the whole cache and regenerates it from ObjectSpace if not running weak-link-caching. If running weaklink-caching then it will only removes the dead links.
948
948
  def clean_all
949
949
  self.clean(@objects.keys)
950
950
  end
data/lib/knj/strings.rb CHANGED
@@ -1,6 +1,6 @@
1
1
  #encoding: utf-8
2
2
 
3
- require "php4r" if !Kernel.const_defined?(:Php4r)
3
+ Knj.gem_require "php4r" if !Kernel.const_defined?(:Php4r)
4
4
 
5
5
  #This module contains various methods to escape, change or treat strings.
6
6
  module Knj::Strings
@@ -334,4 +334,9 @@ module Knj::Strings
334
334
 
335
335
  return false
336
336
  end
337
+
338
+ #Takes a string and converts it to a safe string for filenames.
339
+ def self.sanitize_filename(filename)
340
+ return filename.gsub(/[^0-9A-z.\-]/, '_').gsub("\\", "_")
341
+ end
337
342
  end
data/lib/knj/web.rb CHANGED
@@ -187,8 +187,8 @@ class Knj::Web
187
187
 
188
188
  #Redirects to another URL.
189
189
  #===Examples
190
- # _hb.redirect("someotherpage.rhtml")
191
- # _hb.redirect("newpage.rhtml", :perm => true)
190
+ # Knj::Web.redirect("someotherpage.rhtml")
191
+ # Knj::Web.redirect("newpage.rhtml", :perm => true)
192
192
  def self.redirect(url, args = {})
193
193
  #Header way
194
194
  begin
@@ -546,13 +546,13 @@ class Knj::Web
546
546
 
547
547
  agent = servervar["HTTP_USER_AGENT"].to_s.downcase
548
548
 
549
- if agent.index("webkit") != nil
549
+ if agent.include?("webkit") != nil
550
550
  return "webkit"
551
- elsif agent.index("gecko") != nil
551
+ elsif agent.include?("gecko") != nil
552
552
  return "gecko"
553
- elsif agent.index("msie") != nil
553
+ elsif agent.include?("msie") != nil
554
554
  return "msie"
555
- elsif agent.index("w3c") != nil or agent.index("baiduspider") != nil or agent.index("googlebot") != nil or agent.index("bot") != nil
555
+ elsif agent.include?("w3c") != nil or agent.include?("baiduspider") != nil or agent.include?("googlebot") != nil or agent.include?("bot") != nil
556
556
  return "bot"
557
557
  else
558
558
  #print "Unknown agent: #{agent}"
@@ -568,12 +568,12 @@ class Knj::Web
568
568
 
569
569
  agent = servervar["HTTP_USER_AGENT"].to_s.downcase
570
570
 
571
- if agent.index("(windows;") != nil or agent.index("windows nt") != nil
571
+ if agent.include?("(windows;") != nil or agent.include?("windows nt") != nil
572
572
  return {
573
573
  "os" => "win",
574
574
  "title" => "Windows"
575
575
  }
576
- elsif agent.index("linux") != nil
576
+ elsif agent.include?("linux") != nil
577
577
  return {
578
578
  "os" => "linux",
579
579
  "title" => "Linux"
@@ -583,12 +583,13 @@ class Knj::Web
583
583
  raise "Unknown OS: #{agent}"
584
584
  end
585
585
 
586
+ #Returns various information about the current browser. Currently only works with the Hayabusa-project.
586
587
  def self.browser(servervar = nil)
587
588
  servervar = _server if !servervar
588
589
  raise "Could not figure out meta data." if !servervar
589
590
  agent = servervar["HTTP_USER_AGENT"].to_s.downcase
590
591
 
591
- if match = agent.index("knj:true") != nil
592
+ if match = agent.include?("knj:true")
592
593
  browser = "bot"
593
594
  title = "Bot"
594
595
  version = "KnjHttp"
@@ -600,6 +601,10 @@ class Knj::Web
600
601
  browser = "firefox"
601
602
  title = "Mozilla Firefox"
602
603
  version = match[1]
604
+ elsif servervar["HTTP_ACCEPT"] == "*/*" and servervar["HTTP_ACCEPT_LANGUAGE"] == "zh-cn,zh-hk,zh-tw,en-us" and servervar["HTTP_USER_AGENT"] == "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1)" and (servervar["REMOTE_ADDR"][0,10] == "114.80.93." or servervar["HTTP_X_FORWARDED_FOR"][0,10] == "114.80.93.")
605
+ browser = "bot"
606
+ title = "bot"
607
+ version = "(unknown annoying bot from China)"
603
608
  elsif match = agent.match(/msie\s*(\d+\.\d+)/)
604
609
  browser = "ie"
605
610
  title = "Microsoft Internet Explorer"
@@ -612,15 +617,15 @@ class Knj::Web
612
617
  browser = "bot"
613
618
  title = "Bot"
614
619
  version = "Wget #{match[1]}"
615
- elsif agent.index("baiduspider") != nil
620
+ elsif agent.include?("baiduspider")
616
621
  browser = "bot"
617
622
  title = "Bot"
618
623
  version = "Baiduspider"
619
- elsif agent.index("googlebot") != nil
624
+ elsif agent.include?("googlebot")
620
625
  browser = "bot"
621
626
  title = "Bot"
622
627
  version = "Googlebot"
623
- elsif agent.index("gidbot") != nil
628
+ elsif agent.include?("gidbot")
624
629
  browser = "bot"
625
630
  title = "Bot"
626
631
  version = "GIDBot"
@@ -632,47 +637,47 @@ class Knj::Web
632
637
  browser = "safari"
633
638
  title = "Safari"
634
639
  version = match[1]
635
- elsif agent.index("iPad") != nil
640
+ elsif agent.include?("iPad")
636
641
  browser = "safari"
637
642
  title = "Safari (iPad)"
638
643
  version = "ipad"
639
- elsif agent.index("bingbot") != nil
644
+ elsif agent.include?("bingbot")
640
645
  browser = "bot"
641
646
  title = "Bot"
642
647
  version = "Bingbot"
643
- elsif agent.index("yahoo! slurp") != nil
648
+ elsif agent.include?("yahoo! slurp")
644
649
  browser = "bot"
645
650
  title = "Bot"
646
651
  version = "Yahoo! Slurp"
647
- elsif agent.index("hostharvest") != nil
652
+ elsif agent.include?("hostharvest")
648
653
  browser = "bot"
649
654
  title = "Bot"
650
655
  version = "HostHarvest"
651
- elsif agent.index("exabot") != nil
656
+ elsif agent.include?("exabot")
652
657
  browser = "bot"
653
658
  title = "Bot"
654
659
  version = "Exabot"
655
- elsif agent.index("dotbot") != nil
660
+ elsif agent.include?("dotbot")
656
661
  browser = "bot"
657
662
  title = "Bot"
658
663
  version = "DotBot"
659
- elsif agent.index("msnbot") != nil
664
+ elsif agent.include?("msnbot")
660
665
  browser = "bot"
661
666
  title = "Bot"
662
667
  version = "MSN bot"
663
- elsif agent.index("yandexbot") != nil
668
+ elsif agent.include?("yandexbot")
664
669
  browser = "bot"
665
670
  title = "Bot"
666
671
  version = "Yandex Bot"
667
- elsif agent.index("mj12bot") != nil
672
+ elsif agent.include?("mj12bot")
668
673
  browser = "bot"
669
674
  title = "Bot"
670
675
  version = "Majestic12 Bot"
671
- elsif agent.index("facebookexternalhit") != nil
676
+ elsif agent.include?("facebookexternalhit")
672
677
  browser = "bot"
673
678
  title = "Bot"
674
679
  version = "Facebook Externalhit"
675
- elsif agent.index("sitebot") != nil
680
+ elsif agent.include?("sitebot")
676
681
  browser = "bot"
677
682
  title = "Bot"
678
683
  version = "SiteBot"
@@ -688,7 +693,7 @@ class Knj::Web
688
693
  browser = "bot"
689
694
  title = "AhrefsBot"
690
695
  version = match[1]
691
- elsif agent.index("sosospider") != nil
696
+ elsif agent.include?("sosospider")
692
697
  browser = "bot"
693
698
  title = "Bot"
694
699
  version = "Sosospider"
@@ -700,7 +705,7 @@ class Knj::Web
700
705
 
701
706
  os = nil
702
707
  os_version = nil
703
- if agent.index("linux") != nil
708
+ if agent.include?("linux") != nil
704
709
  os = "linux"
705
710
  elsif match = agent.match(/mac\s+os\s+x\s+([\d_+])/)
706
711
  os = "mac"
@@ -39,7 +39,7 @@
39
39
  _get["path"] = Base64.decode64(_get["path64"])
40
40
  end
41
41
 
42
-
42
+ require "digest/md5"
43
43
  idstr = Digest::MD5.hexdigest("#{_get["path"]}_#{_get["smartsize"].to_i}_#{_get["width"].to_i}_#{_get["height"].to_i}_#{_get["maxwidth"].to_i}_#{_get["maxheight"].to_i}_#{_get["rounded_corners"].to_i}_#{_get["border"].to_i}_#{_get["border_color"]}")
44
44
 
45
45
  if !_get["path"] or !File.exists?(_get["path"])
@@ -87,25 +87,24 @@
87
87
 
88
88
  if !tmp_use or tmp_write or force
89
89
  blob_cont = nil
90
- Knj::Process_meta.new("debug_err" => true) do |subproc|
91
- subproc.static("Object", "require", "rubygems")
92
- subproc.static("Object", "require", "#{File.dirname(Knj::Os.realpath(__FILE__))}/../../knjrbfw.rb")
93
- subproc.static("Object", "require", "knj/autoload")
94
- subproc.static("Dir", "chdir", File.dirname(__FILE__))
90
+ Ruby_process::Cproxy.run do |data|
91
+ subproc = data[:subproc]
92
+ subproc.static(:Object, :require, "rubygems")
93
+ subproc.static(:Object, :require, "#{Knj.knjrbfw_path}/../knjrbfw.rb")
94
+ subproc.static(:Object, :require, "RMagick")
95
+ subproc.static(:Dir, :chdir, File.dirname(__FILE__))
95
96
 
96
- list_proxy = subproc.proxy_from_static("Magick::Image", "read", _get["path"])
97
- pic = subproc.proxy_from_call(list_proxy, "first")
98
- #pic = Magick::Image.read(_get["path"]).first
97
+ pic = subproc.static("Magick::Image", :read, _get["path"]).first
99
98
 
100
99
  if !pic
101
100
  print "Could not open image from '#{_get["path"]}'."
102
101
  exit
103
102
  end
104
103
 
105
- pic._pm_send_noret("format=", "png")
104
+ pic.format = "png"
106
105
 
107
- pic_columns = pic.columns
108
- pic_rows = pic.rows
106
+ pic_columns = pic.columns.__rp_marshal
107
+ pic_rows = pic.rows.__rp_marshal
109
108
 
110
109
  width = pic_columns
111
110
  height = pic_rows
@@ -147,8 +146,7 @@
147
146
  end
148
147
 
149
148
  if height != pic_rows or width != pic_columns
150
- pic = subproc.proxy_from_call(pic, "resize_to_fit", width.to_i, height.to_i)
151
- #pic = pic.resize_to_fit(width.to_i, height.to_i)
149
+ pic = pic.resize_to_fit(width.to_i, height.to_i)
152
150
  end
153
151
 
154
152
  if _get["rounded_corners"]
@@ -159,31 +157,15 @@
159
157
  args[:border_color] = _get["border_color"]
160
158
  end
161
159
 
162
- #Spawn arguments-hash for Knj::Image.rounded_corners in subprocess.
163
- proxy_hash = subproc.new("{}", args)
164
-
165
160
  #Call rounded_corners with the proxy-hash.
166
- subproc.static_noret("Knj::Image", "rounded_corners", proxy_hash)
167
- #Knj::Image.rounded_corners(args)
161
+ subproc.static("Knj::Image", :rounded_corners, args)
168
162
  end
169
163
 
170
- blob_cont = pic.to_blob
171
- end
172
- end
173
-
174
- if tmp_write and blob_cont
175
- File.open(tmp_path, "w") do |fp|
176
- fp.write(blob_cont)
164
+ pic.write(tmp_path) if tmp_write or force
177
165
  end
178
166
  end
179
167
 
180
- if tmp_use and !force
181
- appsrv.header("Last-Modified", "#{time_orig.httpdate} GMT") if time_orig
182
- appsrv.header("Content-Type", "image/png")
183
- _httpsession.force_content(File.read(tmp_path))
184
- else
185
- appsrv.header("Last-Modified", "#{time_orig.httpdate} GMT") if time_orig
186
- appsrv.header("Content-Type", "image/png")
187
- _httpsession.force_content(blob_cont)
188
- end
168
+ appsrv.header("Last-Modified", "#{time_orig.httpdate} GMT") if time_orig
169
+ appsrv.header("Content-Type", "image/png")
170
+ _httpsession.force_fileread(tmp_path)
189
171
  %>
data/spec/strings_spec.rb CHANGED
@@ -57,4 +57,9 @@ describe "Strings" do
57
57
  res = Knj::Strings.secs_to_human_short_time(120, :mins => false)
58
58
  raise "Expected '0.0t' but got '#{res}'." if res != "0.0t"
59
59
  end
60
+
61
+ it "sanitize_filename" do
62
+ res = Knj::Strings.sanitize_filename('1\2 3/4')
63
+ res.should eql("1_2_3_4")
64
+ end
60
65
  end