knjrbfw 0.0.21 → 0.0.22

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 CHANGED
@@ -1 +1 @@
1
- 0.0.21
1
+ 0.0.22
@@ -5,11 +5,11 @@
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = %q{knjrbfw}
8
- s.version = "0.0.21"
8
+ s.version = "0.0.22"
9
9
 
10
10
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
11
  s.authors = ["Kasper Johansen"]
12
- s.date = %q{2012-03-04}
12
+ s.date = %q{2012-03-16}
13
13
  s.description = %q{Including stuff for HTTP, SSH and much more.}
14
14
  s.email = %q{k@spernj.org}
15
15
  s.extra_rdoc_files = [
@@ -79,10 +79,24 @@ module Knj::ArrayExt
79
79
  end
80
80
  end
81
81
 
82
- adds.each do |key, value|
83
- hash_given[key] = value
82
+ hash_given.merge!(adds)
83
+
84
+ return hash_given
85
+ end
86
+
87
+ #Converts all keys in the given hash to strings.
88
+ def self.hash_str(hash_given)
89
+ adds = {}
90
+
91
+ hash_given.each do |key, val|
92
+ if !key.is_a?(String)
93
+ adds[key.to_s] = val
94
+ hash_given.delete(key)
95
+ end
84
96
  end
85
97
 
98
+ hash_given.merge!(adds)
99
+
86
100
  return hash_given
87
101
  end
88
102
 
@@ -201,7 +215,7 @@ module Knj::ArrayExt
201
215
  Knj::Php.foreach(hash) do |key, val|
202
216
  if val.is_a?(String)
203
217
  begin
204
- hash[key] = Knj::Php.utf8_encode(encoding)
218
+ hash[key] = Knj::Php.utf8_encode(val)
205
219
  rescue Encoding::UndefinedConversionError => e
206
220
  if args["ignore_encoding_errors"]
207
221
  next
@@ -4,15 +4,37 @@ class Knj::Cmd_parser
4
4
 
5
5
  str.lines.each do |line|
6
6
  next if line.match(/^total ([\d\.,]+)(M|k|G|)$/)
7
- match = line.match(/^(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)\s+(\d+)\s+(.+)\s+([^\W].+?)\s+([\d\.,]+)(M|k|G|K|)\s+((\d+)-(\d+)-(\d+)|(([A-z]{3})\s+(\d+)))\s+(\d+):(\d+)\s+(.+)$/)
7
+ match = line.match(/^(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)\s+(\d+)\s+(.+)\s+([^\W].+?)\s+([\d\.,]+)(M|k|G|K|)\s+((\d+)-(\d+)-(\d+)|(([A-z]{3})\s+(\d+)))\s+((\d+):(\d+)|(\d{4}))\s+(.+)$/)
8
8
  raise "Could not match: '#{line}'." if !match
9
9
 
10
+ year = nil
11
+
12
+ if match[17].to_i > 0
13
+ year = match[17].to_i
14
+ elsif match[26].to_i > 0
15
+ year = match[26].to_i
16
+ end
17
+
18
+ hour = match[24].to_i
19
+ min = match[25].to_i
20
+
10
21
  if match[17] and match[18] and match[19]
11
- time = Time.local(match[17].to_i, match[18].to_i, match[19].to_i, match[23].to_i, match[24].to_i)
22
+ month = match[18].to_i
23
+ date = match[19].to_i
12
24
  elsif match[20] and match[21] and match[22]
13
- time = Time.local(Time.now.year, match[21], match[22].to_i, match[23].to_i, match[24].to_i)
25
+ month = Knj::Datet.month_str_to_no(match[21])
26
+ date = match[22].to_i
27
+ end
28
+
29
+ if !year
30
+ if month > Time.now.month
31
+ year = Time.now.year - 1
32
+ else
33
+ year = Time.now.year
34
+ end
14
35
  end
15
36
 
37
+ time = Time.local(year, month, date, hour, min)
16
38
  bytes = match[14].gsub(",", ".").to_f
17
39
 
18
40
  size_match = match[15]
@@ -50,7 +72,7 @@ class Knj::Cmd_parser
50
72
  :grp => match[13],
51
73
  :size => bytes.to_i,
52
74
  :time => time,
53
- :file => match[25]
75
+ :file => match[27]
54
76
  }
55
77
  end
56
78
 
@@ -1,5 +1,8 @@
1
1
  class Knj::Csv
2
2
  def self.arr_to_csv(arr, del, encl)
3
+ raise "No delimiter given." if !del
4
+ raise "No enclosure given." if !encl
5
+
3
6
  str = ""
4
7
  first = true
5
8
  arr.each do |val|
@@ -11,6 +11,11 @@ class Knj::Datarow
11
11
  return @depending_data
12
12
  end
13
13
 
14
+ def self.autodelete_data
15
+ @autodelete_data = [] if !@autodelete_data
16
+ return @autodelete_data
17
+ end
18
+
14
19
  #This helps various parts of the framework determine if this is a datarow class without requiring it.
15
20
  def is_knj?
16
21
  return true
@@ -33,7 +38,14 @@ class Knj::Datarow
33
38
  methodname = val[:method]
34
39
 
35
40
  if val[:depends]
36
- depending_data << {
41
+ self.depending_data << {
42
+ :colname => colname,
43
+ :classname => classname
44
+ }
45
+ end
46
+
47
+ if val[:autodelete]
48
+ self.autodelete_data << {
37
49
  :colname => colname,
38
50
  :classname => classname
39
51
  }
@@ -106,7 +118,7 @@ class Knj::Datarow
106
118
 
107
119
  if val[:required]
108
120
  colname = "#{classname.to_s.downcase}_id".to_sym if !colname
109
- required_data << {
121
+ self.required_data << {
110
122
  :col => colname,
111
123
  :class => classname
112
124
  }
@@ -378,6 +390,7 @@ class Knj::Datarow
378
390
  sql = "SELECT #{table_str}.*"
379
391
  end
380
392
 
393
+ qargs = nil
381
394
  ret = self.list_helper(d)
382
395
 
383
396
  sql << " FROM #{table_str}"
@@ -389,6 +402,8 @@ class Knj::Datarow
389
402
  case key
390
403
  when "return_sql"
391
404
  #ignore
405
+ when :cloned_ubuf
406
+ qargs = {:cloned_ubuf => true}
392
407
  else
393
408
  raise "Invalid key: '#{key}' for '#{self.name}'. Valid keys are: '#{@columns_sqlhelper_args[:cols].keys.sort}'."
394
409
  end
@@ -418,7 +433,7 @@ class Knj::Datarow
418
433
 
419
434
  if select_col_as_array
420
435
  ids = [] if !block
421
- d.db.q(sql) do |data|
436
+ d.db.q(sql, qargs) do |data|
422
437
  if block
423
438
  block.call(data[:id])
424
439
  else
@@ -437,7 +452,7 @@ class Knj::Datarow
437
452
  return 0
438
453
  end
439
454
 
440
- return d.ob.list_bysql(self.classname, sql, &block)
455
+ return d.ob.list_bysql(self.classname, sql, qargs, &block)
441
456
  end
442
457
 
443
458
  def self.list_helper(d)
@@ -129,7 +129,7 @@ class Knj::Datet
129
129
  #Is a year a leap year in the Gregorian calendar? Copied from Date-class.
130
130
  def self.gregorian_leap?(y)
131
131
  if Date.respond_to?("gregorian_leap?")
132
- return Date.gregorian_leap?
132
+ return Date.gregorian_leap?(y)
133
133
  elsif y % 4 == 0 && y % 100 != 0
134
134
  return true
135
135
  elsif y % 400 == 0
@@ -30,11 +30,11 @@ class Knj::Gettext_threadded
30
30
 
31
31
  cont = nil
32
32
  File.open(pofn, {:encoding => @args[:encoding]}) do |fp|
33
- cont = fp.read
33
+ cont = fp.read.encode("utf-8")
34
34
  end
35
35
 
36
36
  cont.scan(/msgid\s+\"(.+)\"\nmsgstr\s+\"(.+)\"\n\n/) do |match|
37
- @langs[file][match[0]] = match[1]
37
+ @langs[file][match[0]] = match[1].to_s.encode("utf-8")
38
38
  end
39
39
  end
40
40
  end
@@ -2,58 +2,97 @@ class Knj::Google_sitemap
2
2
  attr_reader :doc
3
3
 
4
4
  def initialize(args = {})
5
+ raise "No block given." if !block_given?
6
+
5
7
  @args = args
6
8
 
7
9
  #used for Time.iso8601.
8
10
  require "time"
9
11
 
10
- @doc = REXML::Document.new
11
- @doc << REXML::XMLDecl.new("1.0", "UTF-8")
12
+ #REXML is known to leak memory - use subprocess.
13
+ @subproc = Knj::Process_meta.new("id" => "google_sitemap", "debug_err" => true)
12
14
 
13
- @urlset = @doc.add_element("urlset")
14
- @urlset.add_attributes("xmlns" => "http://www.sitemaps.org/schemas/sitemap/0.9")
15
+ begin
16
+ @subproc.static("Object", "require", "rexml/rexml")
17
+ @subproc.static("Object", "require", "rexml/document")
18
+
19
+ @doc = @subproc.new("REXML::Document")
20
+
21
+ xmldecl = @subproc.new("REXML::XMLDecl", "1.0", "UTF-8")
22
+ @doc._pm_send_noret("<<", xmldecl)
23
+
24
+ urlset = @subproc.proxy_from_call(@doc, "add_element", "urlset")
25
+ urlset._pm_send_noret("add_attributes", {"xmlns" => "http://www.sitemaps.org/schemas/sitemap/0.9"})
26
+
27
+ @root = @subproc.proxy_from_call(@doc, "root")
28
+ yield(self)
29
+ ensure
30
+ @doc = nil
31
+ @root = nil
32
+ @subproc.destroy
33
+ @subproc = nil
34
+ end
15
35
  end
16
36
 
17
37
  def add_url(url_value, lastmod_value, cf_value = nil, priority_value = nil)
18
- el = REXML::Element.new("url")
19
-
20
- loc = el.add_element("loc")
21
- loc.text = url_value
22
-
23
38
  if !lastmod_value or lastmod_value.to_i == 0
24
39
  raise sprintf("Invalid date: %1$s, url: %2$s", lastmod_value.to_s, url_value)
25
40
  end
26
41
 
27
- lm = el.add_element("lastmod")
42
+ el = @subproc.new("REXML::Element", "url")
43
+
44
+ loc = @subproc.proxy_from_call(el, "add_element", "loc")
45
+ loc._pm_send_noret("text=", url_value)
46
+
47
+ lm = @subproc.proxy_from_call(el, "add_element", "lastmod")
28
48
  if @args.key?(:date_min) and @args[:date_min] > lastmod_value
29
49
  lastmod_value = @args[:date_min]
30
50
  end
31
51
 
32
- lm.text = lastmod_value.iso8601
52
+ lm._pm_send_noret("text=", lastmod_value.iso8601)
33
53
 
34
54
  if cf_value
35
- cf = el.add_element("changefreq")
36
- cf.text = cf_value
55
+ cf = @subproc.proxy_from_call(el, "add_element", "changefreq")
56
+ cf._pm_send_noret("text=", cf_value)
37
57
  end
38
58
 
39
59
  if priority_value
40
- priority = el.add_element("priority")
41
- priority.text = priority_value
60
+ priority = @subproc.proxy_from_call("el", "add_element", "priority")
61
+ priority._pm_send_noret("text=", priority_value)
42
62
  end
43
63
 
44
- @doc.root << el
64
+ @root._pm_send_noret("<<", el)
45
65
  end
46
66
 
67
+ #This will return a non-human-readable XML-string.
47
68
  def to_xml
48
69
  return @doc.to_s
49
70
  end
50
71
 
72
+ #This will return a non-human-readable XML-string.
51
73
  def to_s
52
74
  return @doc.to_s
53
75
  end
54
76
 
77
+ #This will print the result.
55
78
  def write
56
- writer = REXML::Formatters::Pretty.new(5)
57
- writer.write(@doc, $stdout)
79
+ #Require and spawn StringIO in the subprocess.
80
+ @subproc.static("Object", "require", "stringio")
81
+ string_io = @subproc.spawn_object("StringIO")
82
+
83
+ #We want a human-readable print.
84
+ writer = @subproc.spawn_object("REXML::Formatters::Pretty", 5)
85
+ writer._pm_send_noret("write", @doc, string_io)
86
+
87
+ #Prepare printing by rewinding StringIO to read from beginning.
88
+ string_io._pm_send_noret("rewind")
89
+
90
+ #Buffer results from subprocess in order to speed up printing.
91
+ string_io._process_meta_block_buffer_use = true
92
+
93
+ #Print out the result in bits to avoid raping the memory (subprocess is already raped - no question there...).
94
+ string_io._pm_send_noret("each", 4096) do |str|
95
+ print str
96
+ end
58
97
  end
59
98
  end
@@ -33,6 +33,14 @@ class Knj::Http2
33
33
 
34
34
  raise "No host was given." if !@args[:host]
35
35
  self.reconnect
36
+
37
+ if block_given?
38
+ begin
39
+ yield(self)
40
+ ensure
41
+ self.destroy
42
+ end
43
+ end
36
44
  end
37
45
 
38
46
  def socket_working?
@@ -49,6 +57,25 @@ class Knj::Http2
49
57
  return true
50
58
  end
51
59
 
60
+ def destroy
61
+ @args = nil
62
+ @cookies = nil
63
+ @debug = nil
64
+ @mutex = nil
65
+ @uagent = nil
66
+ @keepalive_timeout = nil
67
+ @request_last = nil
68
+
69
+ @sock.close if @sock and !@sock.closed?
70
+ @sock = nil
71
+
72
+ @sock_plain.close if @sock_plain and !@sock_plain.closed?
73
+ @sock_plain = nil
74
+
75
+ @sock_ssl.close if @sock_ssl and !@sock_ssl.closed?
76
+ @sock_ssl = nil
77
+ end
78
+
52
79
  #Reconnects to the host.
53
80
  def reconnect
54
81
  print "Http2: Reconnect.\n" if @debug
@@ -106,19 +133,25 @@ class Knj::Http2
106
133
  end
107
134
 
108
135
  def get(addr, args = {})
109
- @mutex.synchronize do
110
- header_str = "GET /#{addr} HTTP/1.1#{@nl}"
111
- header_str << self.header_str(self.default_headers(args), args)
112
- header_str << "#{@nl}"
113
-
114
- print "Http2: Writing headers.\n" if @debug
115
- self.write(header_str)
116
-
117
- print "Http2: Reading response.\n" if @debug
118
- resp = self.read_response(args)
136
+ begin
137
+ @mutex.synchronize do
138
+ header_str = "GET /#{addr} HTTP/1.1#{@nl}"
139
+ header_str << self.header_str(self.default_headers(args), args)
140
+ header_str << "#{@nl}"
141
+
142
+ print "Http2: Writing headers.\n" if @debug
143
+ self.write(header_str)
144
+
145
+ print "Http2: Reading response.\n" if @debug
146
+ resp = self.read_response(args)
147
+
148
+ print "Http2: Done with get request.\n" if @debug
149
+ return resp
150
+ end
151
+ rescue Knj::Errors::Retry => e
152
+ print "Redirecting to: #{e.message}\n"
119
153
 
120
- print "Http2: Done with get request.\n" if @debug
121
- return resp
154
+ return self.get(e.message, args)
122
155
  end
123
156
  end
124
157
 
@@ -159,59 +192,67 @@ class Knj::Http2
159
192
  end
160
193
 
161
194
  def post(addr, pdata = {}, args = {})
162
- @mutex.synchronize do
163
- praw = ""
164
- pdata.each do |key, val|
165
- praw << "&" if praw != ""
166
- praw << "#{Knj::Web.urlenc(key)}=#{Knj::Web.urlenc(val)}"
195
+ begin
196
+ @mutex.synchronize do
197
+ praw = ""
198
+ pdata.each do |key, val|
199
+ praw << "&" if praw != ""
200
+ praw << "#{Knj::Web.urlenc(key)}=#{Knj::Web.urlenc(val)}"
201
+ end
202
+
203
+ header_str = "POST /#{addr} HTTP/1.1#{@nl}"
204
+ header_str << self.header_str(self.default_headers(args).merge("Content-Length" => praw.length), args)
205
+ header_str << "#{@nl}"
206
+ header_str << praw
207
+
208
+ self.write(header_str)
209
+ return self.read_response(args)
167
210
  end
168
-
169
- header_str = "POST /#{addr} HTTP/1.1#{@nl}"
170
- header_str << self.header_str(self.default_headers(args).merge("Content-Length" => praw.length), args)
171
- header_str << "#{@nl}"
172
- header_str << praw
173
-
174
- self.write(header_str)
175
- return self.read_response(args)
211
+ rescue Knj::Errors::Retry => e
212
+ return self.get(e.message, args)
176
213
  end
177
214
  end
178
215
 
179
216
  def post_multipart(addr, pdata, args = {})
180
- @mutex.synchronize do
181
- boundary = Digest::MD5.hexdigest(Time.now.to_f.to_s)
182
-
183
- praw = ""
184
- pdata.each do |key, val|
185
- praw << "--#{boundary}#{@nl}"
217
+ begin
218
+ @mutex.synchronize do
219
+ boundary = Digest::MD5.hexdigest(Time.now.to_f.to_s)
186
220
 
187
- if val.class.name == "Tempfile" and val.respond_to?("original_filename")
188
- praw << "Content-Disposition: form-data; name=\"#{key}\"; filename=\"#{val.original_filename}\";#{@nl}"
189
- else
190
- praw << "Content-Disposition: form-data; name=\"#{key}\";#{@nl}"
221
+ praw = ""
222
+ pdata.each do |key, val|
223
+ praw << "--#{boundary}#{@nl}"
224
+
225
+ if val.class.name == "Tempfile" and val.respond_to?("original_filename")
226
+ praw << "Content-Disposition: form-data; name=\"#{key}\"; filename=\"#{val.original_filename}\";#{@nl}"
227
+ else
228
+ praw << "Content-Disposition: form-data; name=\"#{key}\";#{@nl}"
229
+ end
230
+
231
+ praw << "Content-Type: text/plain#{@nl}"
232
+ praw << "Content-Length: #{val.length}#{@nl}"
233
+ praw << @nl
234
+
235
+ if val.is_a?(StringIO)
236
+ praw << val.read
237
+ else
238
+ praw << val.to_s
239
+ end
240
+
241
+ praw << @nl
191
242
  end
192
243
 
193
- praw << "Content-Type: text/plain#{@nl}"
194
- praw << "Content-Length: #{val.length}#{@nl}"
195
- praw << @nl
244
+ header_str = "POST /#{addr} HTTP/1.1#{@nl}"
245
+ header_str << "Content-Type: multipart/form-data; boundary=#{boundary}#{@nl}"
246
+ header_str << self.header_str(self.default_headers(args).merge("Content-Length" => praw.length), args)
247
+ header_str << "#{@nl}"
248
+ header_str << praw
249
+ header_str << "--#{boundary}--"
196
250
 
197
- if val.is_a?(StringIO)
198
- praw << val.read
199
- else
200
- praw << val.to_s
201
- end
202
-
203
- praw << @nl
251
+ self.write(header_str)
252
+ return self.read_response(args)
204
253
  end
205
-
206
- header_str = "POST /#{addr} HTTP/1.1#{@nl}"
207
- header_str << "Content-Type: multipart/form-data; boundary=#{boundary}#{@nl}"
208
- header_str << self.header_str(self.default_headers(args).merge("Content-Length" => praw.length), args)
209
- header_str << "#{@nl}"
210
- header_str << praw
211
- header_str << "--#{boundary}--"
212
-
213
- self.write(header_str)
214
- return self.read_response(args)
254
+ rescue Knj::Errors::Retry => e
255
+ return self.get(e.message, args)
215
256
  end
216
257
  end
217
258
 
@@ -313,13 +354,15 @@ class Knj::Http2
313
354
  args[:port] = uri.port if uri.port
314
355
 
315
356
  if !args[:host] or args[:host] == @args[:host]
316
- return self.get(resp.header("location"))
357
+ raise Knj::Errors::Retry, resp.header("location")
317
358
  else
318
359
  http = Knj::Http2.new(args)
319
360
  return http.get(uri.path)
320
361
  end
321
362
  elsif resp.args[:code].to_s == "500"
322
363
  raise "500 - Internal server error."
364
+ elsif resp.args[:code].to_s == "403"
365
+ raise Knj::Errors::NoAccess
323
366
  else
324
367
  return resp
325
368
  end
@@ -428,6 +471,7 @@ class Knj::Http2::Response
428
471
  return @args[:headers][key].first.to_s
429
472
  end
430
473
 
474
+ #Returns true if a header of the given string exists.
431
475
  def header?(key)
432
476
  return true if @args[:headers].key?(key) and @args[:headers][key].first.to_s.length > 0
433
477
  return false