rubyment 0.6.25484655 → 0.6.25503334

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.
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