rubyment 0.6.25484655 → 0.6.25503334

Sign up to get free protection for your applications and to get access to all the features.
Files changed (3) hide show
  1. checksums.yaml +4 -4
  2. data/lib/rubyment.rb +656 -78
  3. metadata +1 -1
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 10899b656c79527134e55de8433e25dd800660c1
4
- data.tar.gz: 1ebc15afed675c406830ebca48e68ff683a1f3eb
3
+ metadata.gz: 1d2807035baddb1234c0afa87f542e51ba5f296d
4
+ data.tar.gz: 4c07bbab0d4c586d9969d7976b79fea603cc94f5
5
5
  SHA512:
6
- metadata.gz: 40061cd1e9adb1331d22821109720eab4313b40af0da7605d06ebb10dd9745bebab219f8c2cba250e910d279f66a5f0711b0b496075f8869258b75b81764ed42
7
- data.tar.gz: 778db1047917e439d7a75bcaec5c87bc90f9a762511b753fa9a847b83cc2666de94411b9460639def90aa73547c73fded6109f7850971b023e8b73aab6ef1f49
6
+ metadata.gz: fa5fa82d9a68feae96c61808c7ee43ed91ab9f5718ffd8bb11621be9f7cb14fe7a0622ee30f7df8331298c5bb3856df379e601514dce8c564e839221edae6a50
7
+ data.tar.gz: e9f1a8161d423e43e9238bc2c6b24d6a8439498cbf0e807724402a975cdfe665656566ec42808a7935179173c008fe271298d1c492cec63999dd1b4ee2378dfb
data/lib/rubyment.rb CHANGED
@@ -1,30 +1,60 @@
1
1
  #!/usr/bin/env ruby
2
2
 
3
3
 
4
- class String
5
- # checks if string is non neutral element.
6
- #
7
- # data from shell input can't be nil
8
- # it will be an "" string. this
9
- # function interprets "" as false
10
- #
11
- # @return [String, nil] self or nil
12
- def nne
13
- !self.empty? && self || nil
4
+ class TrueClass
5
+ # returns +false+ (purpose of simplifying
6
+ # functional programming)
7
+ def false?
8
+ false
14
9
  end
15
10
  end
16
11
 
17
12
 
18
- class Fixnum
19
- # checks if Fixnum is non neutral element.
13
+ class Object
14
+ # returns +self+ if +self+ is not considered
15
+ # to be the neutral element of its class.
16
+ # an object is considered to the neutral
17
+ # element if it answers +true+ to any of
18
+ # a global +asserting_methods+ list.
19
+ # this list is by now the following:
20
+ # [ empty?, :zero?, :false? ]
21
+ # but it will grow as more classes are
22
+ # known to have different +asserting_methods+.
23
+ # it returns +nil+ when the element is
24
+ # considered the neutral element.
20
25
  #
21
- # data from shell input can't be nil
22
- # it will be an 0 string. this
23
- # function interprets 0 as false
26
+ # data from other languagues, like most
27
+ # shell input, can't be +nil+ so sometimes
28
+ # "" has to be interpreted as +nil+. so,
29
+ # one example usage of the neutral element
30
+ # concept.
24
31
  #
25
- # @return [Fixnum, nil] self or nil
26
- def nne
27
- !self.zero? && self || nil
32
+ def nne default=nil
33
+ asserting_methods = [
34
+ :empty?,
35
+ :zero?,
36
+ :false?,
37
+ ]
38
+ responds_false_to = asserting_methods.map { |am|
39
+ (self.respond_to? am) && (
40
+ self.method(am).call.negate_me
41
+ ) || nil
42
+ }
43
+ responds_false_to.any? && self || default
44
+ end
45
+
46
+
47
+ # returns nil out of an object.
48
+ # usage examples:
49
+ # "this_parameter_is_nil".to_nil
50
+ def to_nil
51
+ nil
52
+ end
53
+
54
+
55
+ # returns +!self+
56
+ def negate_me
57
+ !self
28
58
  end
29
59
  end
30
60
 
@@ -92,6 +122,8 @@ class Rubyment
92
122
  rv = [e.backtrace.join("\n"), e]
93
123
  stderr.puts "#{__method__} exception backtrace:"
94
124
  stderr.puts rv[0]
125
+ stderr.puts "#{__method__} exception inspection:"
126
+ stderr.puts rv[1].inspect
95
127
  stderr.puts "#{__method__} exception message:"
96
128
  stderr.puts rv[1]
97
129
  rv
@@ -100,6 +132,29 @@ class Rubyment
100
132
  end
101
133
 
102
134
 
135
+ # creates a +Proc+ out of a block,
136
+ # where exceptions may be admissible
137
+ # or not, and to be printed or not.
138
+ # it is an interface for the bl*
139
+ # methods above
140
+ # @param [splat] +args+, an splat whose elements are expected to be +blea_args+ and +blocks_args+:
141
+ # +blea_args+:: [Array] args to be used internally, which are expected to be:
142
+ # +exception_admitted+:: [Boolean]
143
+ # +output_exception+:: [Boolean]
144
+ # +blocks_args+:: [splat] args to be forwarded to the block call
145
+ # @return [Proc]
146
+ def blea *args, &block
147
+ blea_args, *block_args = args
148
+ blea_args ||= blea_args.nne []
149
+ exception_admitted, output_exception = blea_args
150
+ exception_admitted ||= exception_admitted.nne
151
+ output_exception ||= output_exception.nne
152
+ ble_method = output_exception && :bloe || :blef
153
+ bl_to_call = exception_admitted && ble_method || :bl
154
+ send bl_to_call, *block_args, &block
155
+ end
156
+
157
+
103
158
  # runs a block error free
104
159
  # (returns nil if exception happens)
105
160
  def runef *args, &block
@@ -146,6 +201,22 @@ class Rubyment
146
201
  end
147
202
 
148
203
 
204
+ # creates and runs a +Proc+ out of a block,
205
+ # where exceptions may be admissible
206
+ # or not, and to be printed or not.
207
+ # it is an interface for the run*
208
+ # methods above
209
+ # @param [splat] +args+, an splat whose elements are expected to be +blea_args+ and +blocks_args+:
210
+ # +blea_args+:: [Array] args to be used internally, which are expected to be:
211
+ # +exception_admitted+:: [Boolean]
212
+ # +output_exception+:: [Boolean]
213
+ # +blocks_args+:: [splat] args to be forwarded to the block call
214
+ # @return the value returned by the block
215
+ def runea *args, &block
216
+ (blea *args, &block).call
217
+ end
218
+
219
+
149
220
  # invoke first arg with following args
150
221
  # used by initialize
151
222
  def invoke args=ARGV
@@ -220,6 +291,19 @@ class Rubyment
220
291
  end
221
292
 
222
293
 
294
+ # compares the version of current rubyment with a given version.
295
+ # so users of rubyment can test if their code will run with
296
+ # the rubyment installed on the system.
297
+ # @param [splat] args, a list of object whose elements are expected to be:
298
+ # +major_version+:: [String]
299
+ # +minor_version+:: [String]
300
+ #
301
+ # @return [Bool] +true+ if rubyment (+self+) version is at least the version give as parameter, +false+ otherwise
302
+ def version_at_least *args
303
+ Gem::Version.new(version []) >= Gem::Version.new(version args)
304
+ end
305
+
306
+
223
307
  # enables the possibility to inkove a second method with
224
308
  # the results of a first one. eg, the results of a method
225
309
  # called file_permissions_octal which returns without output
@@ -240,6 +324,21 @@ class Rubyment
240
324
  end
241
325
 
242
326
 
327
+ # returns an enumeration of +method_name+ for each element in
328
+ # the enumeration +a+. Useful for heterogeneous arrays
329
+ # (like arrays of Strings, of Hashes, of Arrays and so on
330
+ def array_map a, method_name, method_args = nil
331
+ a.map {|e| e.method(method_name).call *method_args }
332
+ end
333
+
334
+
335
+ # the same as #array_map (but takes all arguments at once)
336
+ def array_maps args=ARGV
337
+ a, method_name, method_args = args
338
+ array_map a, method_name, method_args
339
+ end
340
+
341
+
243
342
  # reads a uri (if 'open-uri' available, otherwise, just do a normal File.read)
244
343
  # @param [Array] args, an +Array+ whose elements are expected to be:
245
344
  # +uri+:: [String, nil] uri or path of the file
@@ -270,6 +369,31 @@ class Rubyment
270
369
  end
271
370
 
272
371
 
372
+ # reads the contents of a file. if the file
373
+ # doesn't exist, writes to the file.
374
+ # note: the file may get overwritten with the
375
+ # same contents in some situations (not if
376
+ # +contents+ is +nil+).
377
+ # @param [splat] +args+::, an splat whose elements are expected to be:
378
+ # +filepath+:: [String] uri (if +'open-uri'+ installed) or local path to a file
379
+ # +username+:: [String] basic http authentication username
380
+ # +password+:: [String] basic http authentication password
381
+ # @return [String] file contents at the end of the process.
382
+ def file_read_or_write *args
383
+ filepath, contents, username, password = args
384
+ existing_file = file_read [
385
+ filepath,
386
+ username,
387
+ password,
388
+ "return on rescue".to_nil,
389
+ "return on dir".to_nil,
390
+ ]
391
+ file_contents ||= existing_file || contents
392
+ contents && (File.write filepath, file_contents)
393
+ file_contents
394
+ end
395
+
396
+
273
397
  # if file is a nonexisting filepath, or by any reason
274
398
  # throws any exception, it will be treated as contents
275
399
  # instead, and the filename will treated as ""
@@ -315,11 +439,57 @@ class Rubyment
315
439
  end
316
440
 
317
441
 
442
+ def files_in_paths paths, reject_dirs=false
443
+ require 'find'
444
+ paths = paths.map {|path| Find.find(path).entries rescue [] }.flatten 1
445
+ reject_dirs && paths.reject{|path| File.directory? path} || paths
446
+ end
447
+
448
+
449
+ def files_in_paths_reject_dirs paths
450
+ files_in_paths paths, true
451
+ end
452
+
453
+
454
+ def files_call_in_paths paths, method, reject_dirs=false
455
+ paths = reject_dirs && (files_in_paths_reject_dirs paths) || paths
456
+ (files_in_paths paths).map {|path| method.call path }
457
+ end
458
+
459
+
460
+ def files_dirnames_in_paths paths, reject_dirs=false
461
+ # (files_in_paths paths).map {|path| File.dirname path }
462
+ files_call_in_paths paths, File.method(:dirname), reject_dirs
463
+ end
464
+
465
+
466
+ def files_basenames_in_paths paths, reject_dirs=false
467
+ files_call_in_paths paths, File.method(:basename), reject_dirs
468
+ end
469
+
470
+
471
+ def filename_replacer
472
+ [/[^0-9A-Za-z\-\.\/]/, "_" ]
473
+ end
474
+
475
+
318
476
  # returns a string having the current backtrace, for debugging.
319
477
  def backtrace
320
478
  Thread.current.backtrace.join("\n")
321
479
  end
322
480
 
481
+ def caller_labels begin_range=1, range_size=1
482
+ caller_locations(begin_range, range_size).map(&:label)
483
+ end
484
+
485
+ # return the last_called function
486
+ def caller_label *args
487
+ default, reserved = *args
488
+ default ||= 3
489
+ caller_labels(default, 1)[0]
490
+ end
491
+
492
+
323
493
  # returns a Class object out of class_name (or itself if it is already
324
494
  # a class)
325
495
  def to_class args=ARGV
@@ -333,17 +503,18 @@ class Rubyment
333
503
 
334
504
 
335
505
  # returns a Method (object.method if object is
336
- # given). give self as object to look up
337
- # at the current context
338
- # args:
339
- # [ name (String), object (Object) ]
340
- # returns:
506
+ # given) matching the name. Give +self+ as object
507
+ # to look up at the current context
508
+ # @param [Array] args, whose elements are:
509
+ # +name+:: [String, nil]
510
+ # +object+:: [Object]
511
+ # @returns:
341
512
  # method_object (Method)
342
513
  def to_object_method args=ARGV
343
514
  stderr = @memory[:stderr]
344
515
  name, object = containerize args
345
516
  begin
346
- method = object.method("method").call(name)
517
+ object.method("method").call(name.to_s)
347
518
  rescue NameError => nameError
348
519
  # every object (even nil) has :method,
349
520
  # and every Method has :call: exception
@@ -2032,8 +2203,7 @@ require '#{gem_name}'
2032
2203
  prepend ||= ""
2033
2204
  expected_new_filename = dest_dir + filename
2034
2205
  existing_file = (file_read [filename, nil, user, pw])
2035
- file_contents ||= existing_file || "contents_of:#{filename}"
2036
- File.write filename, file_contents
2206
+ file_contents = file_read_or_write filename, "contents_of:#{filename}", user, pw
2037
2207
  file_backup filename, dest_dir, append, prepend
2038
2208
  new_file_contents = File.read expected_new_filename
2039
2209
  original_permissions = file_permissions_octal filename
@@ -2045,6 +2215,7 @@ require '#{gem_name}'
2045
2215
  ].map(&method("expect_equal")).all?
2046
2216
  (!existing_file) && (FileUtils.rm filename)
2047
2217
  (!keep_new) && (FileUtils.rm expected_new_filename)
2218
+ judgement
2048
2219
  end
2049
2220
 
2050
2221
 
@@ -2069,8 +2240,13 @@ require '#{gem_name}'
2069
2240
  #
2070
2241
  # @return [Method] a method
2071
2242
  def to_method args = ARGV
2072
- method_name_or_method, reserved = args
2073
- method_name_or_method.respond_to?(:call) && method_name_or_method || method(method_name_or_method)
2243
+ method_name_or_method, object, reserved = args
2244
+ (
2245
+ to_object_method [object, method_name_or_method]
2246
+ ) || (
2247
+ method_name_or_method.respond_to?(:call) && method_name_or_method
2248
+ ) ||
2249
+ method(method_name_or_method)
2074
2250
  end
2075
2251
 
2076
2252
 
@@ -2088,13 +2264,16 @@ require '#{gem_name}'
2088
2264
  # @param [Array] +args+, an +Array+ whose elements are expected to be:
2089
2265
  # +processing_arg+:: [Object]
2090
2266
  # +method+:: [Method, String]
2091
- # +method_args+:: [Method, String]
2267
+ # +method_args+:: [Array] args to be given to the +transform_method_name+
2268
+ # +on_object+:: [String, Boolean]
2092
2269
  #
2093
2270
  # @return [String] +processing_arg+
2094
- def transform_call args = ARGV
2095
- processing_arg, method, method_args = args
2271
+ def test__transform_call args = ARGV
2272
+ processing_arg, method, method_args, on_object = args
2273
+ object_arg = on_object.nne && processing_arg || nil
2274
+ p args
2096
2275
  to_method(
2097
- [method]).call(
2276
+ [method, object_arg]).call(
2098
2277
  [processing_arg] + method_args
2099
2278
  )
2100
2279
  end
@@ -2106,23 +2285,32 @@ require '#{gem_name}'
2106
2285
  # +content_type+:: [String, nil] mime type of payload (default +text/plain+)
2107
2286
  # +version+:: [String, nil] http protocol version (+1.1+ by default)
2108
2287
  # +code+:: [String, nil] response code (+"200 OK"+ by default)
2109
- # +eol+:: [String, nil]
2288
+ # +keep_alive+:: [Boolean] right not unsupported, always close the connection
2289
+ # +eol+:: [String, nil] response code (+"\r\n"+ by default/on +nil+)
2110
2290
  #
2111
- # @return [String] http_response
2291
+ # @return [Array] response with proper headers in an array where each element is a response line
2112
2292
  def http_OK_response args = ARGV
2113
- payload, content_type, code, version, eol = args
2293
+ payload, content_type, code, version, keep_alive, debug, eol = args
2294
+ stderr = @memory[:stderr]
2295
+ debug.nne && (stderr.puts "#{__method__} starting")
2296
+ debug.nne && (stderr.puts args.inspect)
2114
2297
  payload ||= ""
2298
+ payload = payload.to_s
2115
2299
  content_type ||= "text/plain"
2116
2300
  version ||= "1.1"
2117
2301
  code ||= "200 OK"
2118
2302
  eol ||= "\r\n"
2119
- [
2303
+ rv = [
2120
2304
  "HTTP/#{version} #{code}",
2121
2305
  "Content-Type: #{content_type};" +
2122
2306
  " charset=#{payload.encoding.name.downcase}",
2123
2307
  "Content-Length: #{payload.bytesize}",
2124
- !keep_alive && "Connection: close"
2125
- ].join eol
2308
+ keep_alive.negate_me && "Connection: close",
2309
+ "",
2310
+ "#{payload}"
2311
+ ]
2312
+ debug.nne && (stderr.puts "#{__method__} returning")
2313
+ rv.join eol
2126
2314
  end
2127
2315
 
2128
2316
 
@@ -2153,6 +2341,40 @@ require '#{gem_name}'
2153
2341
  end
2154
2342
 
2155
2343
 
2344
+ # gets an input from +io+ and writes it back to the same +io+
2345
+ # supports an optional +replace+ and +replacement+ parameter
2346
+ # that can be used to make simple changes to the echoing output
2347
+ # @param [Array] +args+, an +Array+ whose elements are expected to be:
2348
+ # +io+:: [IO] any +IO+, like a +Socket+, returned by #TCPServer::accept
2349
+ # +debug+:: [Object] if evals to false (or empty string), won't print debug information
2350
+ # +transform_method_name+:: [String]
2351
+ # +transform_method_args+:: [Array] args to be given to the ++transform_method_name+
2352
+ # +happy_with_request+:: [String, nil] if nil, +eol+ is used.
2353
+ #
2354
+ # @return [nil]
2355
+ def io_transform args = ARGV
2356
+ io,
2357
+ debug,
2358
+ happy_with_request,
2359
+ transform_method_name,
2360
+ transform_method_args,
2361
+ reserved = args
2362
+ stderr = @memory[:stderr]
2363
+ debug.nne && (stderr.puts "#{__method__} starting")
2364
+ debug.nne && (stderr.puts "transform_method_name: #{transform_method_name}")
2365
+ debug.nne && (stderr.puts "transform_method_args: #{transform_method_args.inspect}")
2366
+ io_forward [[io], io, debug, happy_with_request, reserved,
2367
+ :test__transform_call, [
2368
+ transform_method_name,
2369
+ transform_method_args,
2370
+ "on_object:true",
2371
+ ]
2372
+ ]
2373
+ debug.nne && (stderr.puts "#{__method__} returning")
2374
+ nil
2375
+ end
2376
+
2377
+
2156
2378
  # gets and forwards the input from one IO to a list of IOs
2157
2379
  # @param [Array] +args+, an +Array+ whose elements are expected to be:
2158
2380
  # +ios_out+:: [Array] array of +IO+, where data will be written to.
@@ -2186,9 +2408,9 @@ require '#{gem_name}'
2186
2408
  ios_out.map{ |shared_io_out|
2187
2409
  runoe_threaded(shared_io_out) {|io_out|
2188
2410
  io_out = shared_io_out
2189
- io_out.puts processed_input
2411
+ io_out.print processed_input
2190
2412
  debug.nne && (
2191
- stderr.puts "#{io_out}: response writen."
2413
+ stderr.puts "#{io_out}: #{processed_input.size} bytes: response writen."
2192
2414
  )
2193
2415
  io_out.close
2194
2416
  debug.nne && (
@@ -2202,29 +2424,41 @@ require '#{gem_name}'
2202
2424
  end
2203
2425
 
2204
2426
 
2205
- # gets and puts
2427
+ # gets an input from +io+ and writes it back to the same +io+
2428
+ # supports an optional +replace+ and +replacement+ parameter
2429
+ # that can be used to make simple changes to the echoing output
2206
2430
  # @param [Array] +args+, an +Array+ whose elements are expected to be:
2207
2431
  # +io+:: [IO] any +IO+, like a +Socket+, returned by #TCPServer::accept
2208
- # +method_name_or_method+:: [String, Method] method name or method object
2209
2432
  # +debug+:: [Object] if evals to false (or empty string), won't print debug information
2433
+ # +replace+:: [String]
2434
+ # +replacement+:: [String]
2210
2435
  # +happy_with_request+:: [String, nil] if nil, +eol+ is used.
2211
2436
  #
2212
2437
  # @return [nil]
2213
2438
  def io_echo args = ARGV
2214
- io, debug, happy_with_request, reserved = args
2439
+ io, debug, happy_with_request, replace, replacement, reserved = args
2440
+ # this is an inefficient replacement:
2441
+ replace ||= " "
2442
+ replacement ||= " "
2215
2443
  stderr = @memory[:stderr]
2216
2444
  debug.nne && (stderr.puts "#{__method__} starting")
2217
- # io_forward [[io], io, debug, happy_with_request, reserved, :echo, []]
2218
- io_forward [[io], io, debug, happy_with_request, reserved,
2219
- :gsub!, [" ", "_"]
2445
+ io_transform [
2446
+ io,
2447
+ debug,
2448
+ happy_with_request,
2449
+ :array_maps,
2450
+ [
2451
+ :gsub!, [replace, replacement]
2452
+ ],
2220
2453
  ]
2454
+
2455
+ debug.nne && (stderr.puts "#{__method__} returning")
2221
2456
  nil
2222
2457
  end
2223
2458
 
2224
2459
 
2225
2460
  # writes a response to an IO (e.g.: socket)
2226
2461
  # @param [Array] +args+, an +Array+ whose elements are expected to be:
2227
- # +method_name_or_method+:: [String, Method] method name or method object
2228
2462
  # +debug+:: [Object] if evals to false (or empty string), won't print debug information
2229
2463
  # +reserved+:: [Object] for future use
2230
2464
  # +args_for_http_OK_response+:: [splat] args to be forwarded to #http_OK_response (check it for specification)
@@ -2233,15 +2467,17 @@ require '#{gem_name}'
2233
2467
  def io_http_OK_response args = ARGV
2234
2468
  io, debug, reserved, *args_for_http_OK_response = args
2235
2469
  stderr = @memory[:stderr]
2470
+ debug.nne && (stderr.puts "#{__method__} starting")
2236
2471
  debug.nne && (stderr.puts args.inspect)
2237
2472
  response = http_OK_response args_for_http_OK_response
2238
2473
  debug.nne && (
2239
2474
  stderr.puts response.inspect
2240
2475
  )
2241
- io.print response
2476
+ io.puts response
2242
2477
  debug.nne && (stderr.puts "response writen.")
2243
2478
  io.close
2244
2479
  debug.nne && (stderr.puts "IO closed.")
2480
+ debug.nne && (stderr.puts "#{__method__} returning")
2245
2481
  nil
2246
2482
  end
2247
2483
 
@@ -2266,8 +2502,108 @@ require '#{gem_name}'
2266
2502
  debug,
2267
2503
  callback_method,
2268
2504
  *callback_method_args = args
2505
+
2506
+ tcp_ssl_server [
2507
+ listening_port,
2508
+ ip_addr,
2509
+ debug,
2510
+ "admit non ssl server",
2511
+ callback_method,
2512
+ callback_method_args
2513
+ ]
2514
+ end
2515
+
2516
+
2517
+ # makes an OpenSSL server
2518
+ # @param [splat] +args+, an splat whose elements are expected to be:
2519
+ # +listening_port+:: [String, Integer] port to listen
2520
+ # +ip_addr+:: [String, nil] ip (no hostname) to bind the server. 0, nil, false, empty string will bind to all addresses possible. 0.0.0.0 => binds to all ipv4 . ::0 to all ipv4 and ipv6
2521
+ # +admit_plain+:: [Boolean] if +true+, tries to create a normal +TCPServer+, if not possible to create +SSLServer+ (default: +false+, for preventing unadvertnt non-SSL server creation)
2522
+ # +debug+:: [Object] for future use
2523
+ # +priv_pemfile+:: [String] argument to be given to +OpenSSL::SSL::SSLContext.key+ method, after calling +OpenSSL::PKey::RSA.new+ with it. It's the private key file. letsencrypt example: +"/etc/letsencrypt/live/#{domain}/privkey.pem"+
2524
+ # +cert_pem_file+:: [String] argument to be given to +OpenSSL::SSL::SSLContext.cert+ method, after calling +OpenSSL::X509::Certificate+. It's the "Context certificate" accordingly to its ruby-doc page. letsencrypt example: +"/etc/letsencrypt/live/scatologies.com/fullchain.pem"+
2525
+ # +extra_cert_pem_files+:: [Array] array of strings. Each string will be mapped with +OpenSSL::SSL::SSLContext.new+, and the resulting array is given to +OpenSSL::SSL::SSLContext.extra_chain_cert+. "An Array of extra X509 certificates to be added to the certificate chain" accordingly to its ruby-doc. letsencryptexample: +["/etc/letsencrypt/live/#{domain}/chain.pem"]+
2526
+ # +output_exception+:: [Bool] output exceptions even if they are admitted?
2527
+ #
2528
+ # @return [OpenSSL::SSL::SSLServer] returns an ssl server, which can be used to accept connections.
2529
+ def ssl_make_server *args
2530
+ stderr = @memory[:stderr]
2531
+ listening_port,
2532
+ ip_addr,
2533
+ debug,
2534
+ admit_plain,
2535
+ priv_pemfile,
2536
+ cert_pem_file,
2537
+ extra_cert_pem_files,
2538
+ output_exception,
2539
+ reserved = args
2540
+ debug ||= debug.nne
2541
+ extra_cert_pem_files ||= extra_cert_pem_files.nne []
2542
+ admit_plain ||= admit_plain.nne
2543
+ output_exception ||= (
2544
+ output_exception.nne || admit_plain.negate_me
2545
+ )
2546
+ debug && (stderr.puts "#{__method__} starting")
2547
+
2269
2548
  require 'socket'
2270
- server = TCPServer.new ip_addr, listening_port
2549
+ plain_server = TCPServer.new ip_addr, listening_port
2550
+ ssl_server = runea [admit_plain, output_exception] {
2551
+ require 'openssl'
2552
+ ssl_context = OpenSSL::SSL::SSLContext.new
2553
+ ssl_context.extra_chain_cert =
2554
+ extra_cert_pem_files
2555
+ .map(&File.method(:read))
2556
+ .map(&OpenSSL::X509::Certificate.method(:new))
2557
+ ssl_context.cert = OpenSSL::X509::Certificate
2558
+ .new File.read cert_pem_file
2559
+ ssl_context.key = OpenSSL::PKey::RSA
2560
+ .new File.read priv_pemfile
2561
+ ssl_server = OpenSSL::SSL::SSLServer
2562
+ .new plain_server, ssl_context
2563
+ ssl_server
2564
+ }
2565
+
2566
+ debug && (stderr.puts "#{__method__} returning")
2567
+ ssl_server || admit_plain && plain_server
2568
+ end
2569
+
2570
+
2571
+ # opens an SSL server accepting connections.
2572
+ # @param [Array] +args+, an +Array+ whose elements are expected to be:
2573
+ # +listening_port+:: [String, Integer] port to listen
2574
+ # +ip_addr+:: [String, nil] ip (no hostname) to bind the server. 0, nil, false, empty string will bind to all addresses possible. 0.0.0.0 => binds to all ipv4 . ::0 to all ipv4 and ipv6
2575
+ # +admit_plain+:: [Boolean] if +true+, tries to create a normal +TCPServer+, if not possible to create +SSLServer+ (default: +false+, for preventing unadvertnt non-SSL server creation)
2576
+ # +debug+:: [Object] for future use
2577
+ # +callback_method+:: [String, Method] method to call when a client connects. The method must accept a socket as parameter.
2578
+ # +callback_method_args+:: [Array] args to be given to the call_back_method. Note that the type differs from #tcp_server_plain (which takes splat)
2579
+ #
2580
+ # @return [Thread] returns a Thread object looping for accepting
2581
+ # incoming connections (call join on that object for waiting for its
2582
+ # completion).
2583
+ def tcp_ssl_server args = ARGV
2584
+ stderr = @memory[:stderr]
2585
+ listening_port,
2586
+ ip_addr,
2587
+ debug,
2588
+ admit_plain,
2589
+ callback_method,
2590
+ callback_method_args,
2591
+ priv_pemfile,
2592
+ cert_pem_file,
2593
+ extra_cert_pem_files,
2594
+ output_exception,
2595
+ reserved = args
2596
+
2597
+ server = ssl_make_server(
2598
+ listening_port,
2599
+ ip_addr,
2600
+ debug,
2601
+ admit_plain,
2602
+ priv_pemfile,
2603
+ cert_pem_file,
2604
+ extra_cert_pem_files,
2605
+ output_exception,
2606
+ )
2271
2607
  debug.nne && (stderr.puts server)
2272
2608
  Thread.start {
2273
2609
  loop {
@@ -2284,54 +2620,296 @@ require '#{gem_name}'
2284
2620
  end
2285
2621
 
2286
2622
 
2287
- # opens a TCP client (TCPsocket) to connect to a server
2288
- # @param [Array] +args+, an +Array+ whose elements are expected to be:
2289
- #
2290
- # @return [nil]
2291
- def tcp_client_plain args = ARGV
2292
- listening_port,
2293
- ip_addr,
2294
- reserved,
2295
- debug,
2296
- callback_method,
2297
- *callback_method_args = args
2298
- require 'socket'
2299
- client = TCPSocket.new ip_addr, listening_port
2300
- =begin
2301
- Thread.start {
2302
- to_method([callback_method])
2303
- .call [client]
2304
- }
2305
- =end
2306
- Thread.start {}
2307
- end
2308
-
2309
-
2310
2623
  # test for tcp_server_plain
2311
2624
  def test__tcp_server_plain args = ARGV
2312
- thread = tcp_server_plain [8003, "0", "", "debug", "io_echo", "debug_io_echo"]
2625
+ thread = tcp_server_plain [8003,
2626
+ "0",
2627
+ "reserved".to_nil,
2628
+ "debug",
2629
+ "io_echo",
2630
+ "debug_io_echo",
2631
+ "default happy_with_request".to_nil,
2632
+ " ", #replace
2633
+ "__", #replacement -- will replace empty spaces
2634
+ ]
2313
2635
  thread.join
2636
+ true
2314
2637
  end
2315
2638
 
2639
+ # test for tcp_server_plain (call io_transform)
2640
+ def test__tcp_server_plain__with_io_transform args = ARGV
2641
+ thread = tcp_server_plain [
2642
+ 8003,
2643
+ "0",
2644
+ "",
2645
+ "debug",
2646
+ "io_transform",
2647
+ "debug_io_transform",
2648
+ "default happy_with_request".to_nil,
2649
+ :array_maps,
2650
+ [
2651
+ :gsub!, [" ", "_____"]
2652
+ ]
2653
+ ]
2654
+ thread.join
2655
+ true
2656
+ end
2316
2657
 
2317
2658
  # test for tcp_server_plain
2318
2659
  def test__tcp_server_plain__with_io_http_response args = ARGV
2319
2660
  thread = tcp_server_plain [
2320
2661
  8003, # listening_port
2321
2662
  "0", # ip_addr: all possible
2322
- "", # reserved
2663
+ "reserved".to_nil,
2323
2664
  "debug_tcp_server_plain_arg",
2324
2665
  "io_http_OK_response",
2325
2666
  "debug_io_http_OK_response_arg",
2326
- "reserved_io_http_OK_response_arg",
2327
- "This is the response payload"
2667
+ "reserved_io_http_OK_response_arg".to_nil,
2668
+ "This is the response payload",
2669
+ "dont_keep_alive".to_nil,
2670
+ ]
2671
+ thread.join
2672
+ true
2673
+ end
2674
+
2675
+
2676
+ # test for tcp_server_plain (call #io_transform with
2677
+ # a function that processes an http request and returns
2678
+ # an http_response, by default #http_OK_response)
2679
+ def test__tcp_server_plain__with_http_OK_response args = ARGV
2680
+ http_processing_method,
2681
+ http_processing_method_args,
2682
+ http_server_port,
2683
+ http_ip_addr,
2684
+ reserved = args
2685
+ http_processing_method ||= http_processing_method.nne :http_OK_response
2686
+ http_processing_method_args ||= http_processing_method_args.nne []
2687
+ http_server_port ||= http_server_port.nne 8003
2688
+ http_ip_addr ||= http_ip_addr.nne "0"
2689
+ thread = tcp_server_plain [
2690
+ http_server_port,
2691
+ http_ip_addr,
2692
+ "reserved".to_nil,
2693
+ "debug",
2694
+ "io_transform",
2695
+ "debug_io_transform",
2696
+ "default happy_with_request".to_nil,
2697
+ http_processing_method,
2698
+ http_processing_method_args
2328
2699
  ]
2329
2700
  thread.join
2701
+ true
2702
+ end
2703
+
2704
+
2705
+ # test for tcp_ssl_server (call #io_transform with
2706
+ # a function that processes an http request and returns
2707
+ # an http_response, by default #http_OK_response)
2708
+ # just like #test__tcp_server_plain__with_http_OK_response
2709
+ # but calling directly #tcp_ssl_server
2710
+ def test__tcp_ssl_server__non_ssl args = ARGV
2711
+ http_processing_method,
2712
+ http_processing_method_args,
2713
+ http_server_port,
2714
+ http_ip_addr,
2715
+ reserved = args
2716
+ http_processing_method ||= http_processing_method.nne :http_OK_response
2717
+ http_processing_method_args ||= http_processing_method_args.nne []
2718
+ http_server_port ||= http_server_port.nne 8003
2719
+ http_ip_addr ||= http_ip_addr.nne "0"
2720
+ thread = tcp_ssl_server [
2721
+ http_server_port,
2722
+ http_ip_addr,
2723
+ "debug",
2724
+ "admit non ssl server",
2725
+ "io_transform",
2726
+ [
2727
+ "debug_io_transform",
2728
+ "default happy_with_request".to_nil,
2729
+ http_processing_method,
2730
+ http_processing_method_args
2731
+ ],
2732
+ ]
2733
+ thread.join
2734
+ true
2735
+ end
2736
+
2737
+
2738
+ # returns a sample self signed certificate-private key pair
2739
+ # that once was created with the command (no password, no
2740
+ # expire date):
2741
+ # + openssl req -x509 -nodes -newkey rsa:1024 -keyout pkey.pem -out cert.crt+
2742
+ # @param [splat] +args+::, an splat whose elements are expected to be:
2743
+ # +reserved+:: [splat] reserved for future use
2744
+ # @return [Array] where the first element is a certificate (suitable to be the contents of +cert_pem_file+ in #ssl_make_server) and the second a private key (suitable to be the contents of +priv_pemfile+ in #ssl_make_server)
2745
+ def ssl_sample_self_signed_cert *args
2746
+ self_signed_certificate = <<-ENDHEREDOC
2747
+ -----BEGIN CERTIFICATE-----
2748
+ MIICWDCCAcGgAwIBAgIJAPa0EXsH2MwsMA0GCSqGSIb3DQEBCwUAMEUxCzAJBgNV
2749
+ BAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEwHwYDVQQKDBhJbnRlcm5ldCBX
2750
+ aWRnaXRzIFB0eSBMdGQwHhcNMTgwNjI3MDkzMTEyWhcNMTgwNzI3MDkzMTEyWjBF
2751
+ MQswCQYDVQQGEwJBVTETMBEGA1UECAwKU29tZS1TdGF0ZTEhMB8GA1UECgwYSW50
2752
+ ZXJuZXQgV2lkZ2l0cyBQdHkgTHRkMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKB
2753
+ gQCplOo6dvbM1650qMYLQ8tRycYlHEZH95kUR5E5EEA8yqgimBtx6InpGQi/PejK
2754
+ tk+IXbDrxinXMXqjZxAhCjd7+frSUFwUTZ669PuRaptlkjV1KojXBW5kRERAgYId
2755
+ H7z7QRuK/gWHqTt9zl3WpW2spfWjHY+cnkYdZIWqDBOggwIDAQABo1AwTjAdBgNV
2756
+ HQ4EFgQUAIq0u116/WmTFQ8HC7/XrKl6wB8wHwYDVR0jBBgwFoAUAIq0u116/WmT
2757
+ FQ8HC7/XrKl6wB8wDAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQsFAAOBgQBgA9ID
2758
+ JcreAgjYLxiaAd7fCfLQ1/RYM8YdP9R4Lzg2cu0dCjXoLZqzAEwUg424rPOvf0Pj
2759
+ wnZ3DFJkg1CoN2fH3yLXQ75mhfM7PJXeWoWLTS2wIG/+VIVI+nKJU0RPOM87Mdlq
2760
+ +b6TI5LsGxlJhaxTmzPtkHZLIRdW6iCJTwP+5Q==
2761
+ -----END CERTIFICATE-----
2762
+ ENDHEREDOC
2763
+ private_key = <<-ENDHEREDOC
2764
+ -----BEGIN PRIVATE KEY-----
2765
+ MIICdQIBADANBgkqhkiG9w0BAQEFAASCAl8wggJbAgEAAoGBAKmU6jp29szXrnSo
2766
+ xgtDy1HJxiUcRkf3mRRHkTkQQDzKqCKYG3HoiekZCL896Mq2T4hdsOvGKdcxeqNn
2767
+ ECEKN3v5+tJQXBRNnrr0+5Fqm2WSNXUqiNcFbmRERECBgh0fvPtBG4r+BYepO33O
2768
+ Xdalbayl9aMdj5yeRh1khaoME6CDAgMBAAECgYB+Z80spU6UJFUbCk8NSIx+u6ui
2769
+ L/BHZs1Ja4tZgL6RUfKATuduQgrCoPF/NBOZPsoL+OKO7Nh1WqFyubkxF5+A6BlI
2770
+ BRe/E4K3cChBWyR5ZQyldYUNVV1HBrAhpurW/OX7FInPGo0I5TkR/CJt6xZPgK1n
2771
+ 4lNXFV29gz/LPTJN4QJBANxnUn2xbtBH0xaTX4iIGEH2keLaUftg0b29Ou/MIPn3
2772
+ +z7Ln9K6eknf/OGXAvBP2cnWkTGXAOBmB95s9XDrORMCQQDE+FcWTlSKFywFaxhp
2773
+ nVkDOL+k7Vpn/rKvqKB3JQOrPkovPSo/CHsUVe/r2NEsdJt1SKOs0/xzNe7wSXBa
2774
+ 1tjRAkAHVbTsE+yRJ+LBfJQQUh8kitUeDI/v4q/4NYTxmAR87SDCXTprY+NP9BFR
2775
+ XJovbyjbS7W3RcQ0s5CNeWjNojZbAkA5u3SDJDhhNUOA3xALvMPfTt3VMICkJKIp
2776
+ HGrUITQ/GAXUbMAaM5knr7yfyzAcMJ10NfNLb+L5veAn686TwY9RAkArqoX6cWrd
2777
+ GflH+FhUggqgVrr9XaXkpPUxcpNqAQH/3Yl5pt9jV2VE7eD3chijMGzGJrMUsqFG
2778
+ n8mFEtUKobsK
2779
+ -----END PRIVATE KEY-----
2780
+ ENDHEREDOC
2781
+ [self_signed_certificate, private_key]
2782
+ end
2783
+
2784
+
2785
+ # test for tcp_ssl_server (call #io_transform with
2786
+ # a function that processes an http request and returns
2787
+ # an http_response, by default #http_OK_response)
2788
+ # just like #test__tcp_ssl_server__non_ssl,
2789
+ # calling directly #tcp_ssl_server, but making
2790
+ # mandatory the server to be ssl one.
2791
+ # requires, by default that the certificate and its
2792
+ # private key are found in the current dir, which
2793
+ # can be achieved with:
2794
+ # +openssl req -x509 -nodes -days 365 -newkey rsa:1024 -keyout pkey.pem -out cert.crt+
2795
+ # but if the files don't exist, they will be created
2796
+ # with a sample self signed certificate.
2797
+ def test__tcp_ssl_server__ssl_self_signed args = ARGV
2798
+ http_processing_method,
2799
+ http_processing_method_args,
2800
+ http_server_port,
2801
+ http_ip_addr,
2802
+ priv_pemfile,
2803
+ cert_pem_file,
2804
+ extra_cert_pem_files,
2805
+ reserved = args
2806
+ http_processing_method ||= http_processing_method.nne :http_OK_response
2807
+ http_processing_method_args ||= http_processing_method_args.nne []
2808
+ http_server_port ||= http_server_port.nne 8003
2809
+ http_ip_addr ||= http_ip_addr.nne "0"
2810
+ priv_pemfile ||= priv_pemfile.nne "pkey.pem"
2811
+ cert_pem_file ||= cert_pem_file.nne "cert.crt"
2812
+ cert_contents, pkey_contents = ssl_sample_self_signed_cert
2813
+ file_read_or_write cert_pem_file, cert_contents
2814
+ file_read_or_write priv_pemfile, pkey_contents
2815
+ extra_cert_pem_files ||= extra_cert_pem_files.nne
2816
+ thread = tcp_ssl_server [
2817
+ http_server_port,
2818
+ http_ip_addr,
2819
+ "debug",
2820
+ "admit non ssl server".negate_me,
2821
+ "io_transform",
2822
+ [
2823
+ "debug_io_transform",
2824
+ "default happy_with_request".to_nil,
2825
+ http_processing_method,
2826
+ http_processing_method_args
2827
+ ],
2828
+ priv_pemfile,
2829
+ cert_pem_file,
2830
+ extra_cert_pem_files,
2831
+ "yes, output exceptions",
2832
+ ]
2833
+ thread.join
2834
+ true
2330
2835
  end
2331
2836
 
2332
2837
 
2333
- # test for tcp_server_plain
2334
- def test__tcp_server_plain__with_io_http_response args = ARGV
2838
+ # test for Object::nne
2839
+ def test__object_nne args = ARGV
2840
+ string_neutral = ""
2841
+ string_non_neutral = "xxx"
2842
+ fixnum_neutral = 0
2843
+ fixnum_non_neutral = 1
2844
+ array_neutral = []
2845
+ array_non_neutral = [1, 2]
2846
+ hash_neutral = {}
2847
+ hash_non_neutral = { 1 => 2 }
2848
+ judgement =
2849
+ [
2850
+ [string_neutral.nne, nil, "string_neutral.nne"],
2851
+ [string_non_neutral.nne, string_non_neutral, "string_non_neutral.nne"],
2852
+ [fixnum_neutral.nne, nil, "fixnum_neutral.nne"],
2853
+ [fixnum_non_neutral.nne, fixnum_non_neutral, "fixnum_non_neutral.nne"],
2854
+ [array_neutral.nne, nil, "array_neutral.nne"],
2855
+ [array_non_neutral.nne, array_non_neutral, "array_non_neutral.nne"],
2856
+ [hash_neutral.nne, nil, "hash_neutral.nne"],
2857
+ [hash_non_neutral.nne, hash_non_neutral, "hash_non_neutral.nne"],
2858
+ ].map(&method("expect_equal")).all?
2859
+ end
2860
+
2861
+
2862
+ # test for functions that adds syntatic sugar to
2863
+ # exceptions.
2864
+ def test__rune_functions args = ARGV
2865
+ do_rescue = "rescue"
2866
+ do_output = "output"
2867
+ no_rescue = "no rescue"
2868
+ no_output = "no output"
2869
+ actual = {}
2870
+ expectation = {}
2871
+
2872
+ #working case
2873
+ expected_return = [1, 2, 3]
2874
+ test_case = :rescue_and_output_work
2875
+ actual[test_case] = runea([do_rescue, do_output], expected_return ) {|args| puts "test_case=#{test_case}"; p args }
2876
+ expectation[test_case] = expected_return
2877
+ test_case = :rescue_but_no_output_work
2878
+ actual[test_case] = runea([do_rescue, no_output.to_nil], expected_return ) {|args| puts "test_case=#{test_case}"; p args }
2879
+ expectation[test_case] = expected_return
2880
+ test_case = :effectless_output_but_no_rescue_work
2881
+ actual[test_case] = runea([no_rescue.to_nil, do_output], expected_return ) {|args| puts "test_case=#{test_case}"; p args }
2882
+ expectation[test_case] = expected_return
2883
+ test_case = :no_output_and_no_rescue_work
2884
+ actual[test_case] = runea([no_rescue.to_nil, no_output.to_nil], expected_return ) {|args| puts "test_case=#{test_case}"; p args }
2885
+ expectation[test_case] = expected_return
2886
+
2887
+ # failure cases
2888
+ expected_return = "no_such_method"
2889
+ test_case = :rescue_and_output_fail
2890
+ actual[test_case] = runea([do_rescue, do_output], [1, 2, 3] ) {|args| puts "test_case=#{test_case}"; p args; args.to_nil.no_such_method }[1].name.to_s
2891
+ expectation[test_case] = expected_return
2892
+ test_case = :rescue_but_no_output_fail
2893
+ actual[test_case] = runea([do_rescue, no_output.to_nil], [1, 2, 3] ) {|args| puts "test_case=#{test_case}"; p args ; args.to_nil.no_such_method }.nil? && expected_return
2894
+ expectation[test_case] = expected_return
2895
+ test_case = :effectless_output_but_no_rescue_fail
2896
+ actual[test_case] = begin
2897
+ runea([no_rescue.to_nil, do_output], [1, 2, 3] ) {|args| puts "test_case=#{test_case}"; p args ; args.to_nil.no_such_method }
2898
+ rescue NoMethodError => noMethodError
2899
+ noMethodError.name.to_s
2900
+ end
2901
+ expectation[test_case] = expected_return
2902
+ test_case = :no_output_and_no_rescue_fail
2903
+ actual[test_case] = begin
2904
+ runea([no_rescue.to_nil, no_output.to_nil], [1, 2, 3] ) {|args| puts "test_case=#{test_case}"; p args ; args.to_nil.no_such_method }
2905
+ rescue NoMethodError => noMethodError
2906
+ noMethodError.name.to_s
2907
+ end
2908
+ expectation[test_case] = expected_return
2909
+
2910
+ judgement = actual.keys.map {|test_case|
2911
+ [expectation[test_case], actual[test_case] , test_case]
2912
+ }.map(&method("expect_equal")).all?
2335
2913
  end
2336
2914
 
2337
2915
 
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rubyment
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.6.25484655
4
+ version: 0.6.25503334
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ribamar Santarosa