rubyment 0.6.25503334 → 0.6.25504825
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.
- checksums.yaml +4 -4
- data/lib/rubyment.rb +173 -13
- metadata +1 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 8440fa12588f22767c0266b4216f301dc4061965
|
4
|
+
data.tar.gz: 9457f3e57be36f1cc9a60ba1f394f5b3c2ca4269
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 9919b5731a08a1260fde09610f10ca4c6bf426d593b6fd9ae2bf59cb6149277db755dc3b07460867d1da32ad4ffb0b78167bc99fce8a9547753286859b240c15
|
7
|
+
data.tar.gz: 6d27e4dda449257ad792738fb00f3d4a440e3f3000a66f059022bf29ccfbf3982ce01392e27ad9339f06ebf45ae6941277fb28dc9562e18e74818620b424aa82
|
data/lib/rubyment.rb
CHANGED
@@ -206,6 +206,9 @@ class Rubyment
|
|
206
206
|
# or not, and to be printed or not.
|
207
207
|
# it is an interface for the run*
|
208
208
|
# methods above
|
209
|
+
# in this right moment it is not
|
210
|
+
# yet possible to return the exception
|
211
|
+
# without printing (planned improvement)
|
209
212
|
# @param [splat] +args+, an splat whose elements are expected to be +blea_args+ and +blocks_args+:
|
210
213
|
# +blea_args+:: [Array] args to be used internally, which are expected to be:
|
211
214
|
# +exception_admitted+:: [Boolean]
|
@@ -2520,9 +2523,9 @@ require '#{gem_name}'
|
|
2520
2523
|
# +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
2524
|
# +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
2525
|
# +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
|
+
# +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"+ (now it's accepted to pass the file contents instead, both must work).
|
2527
|
+
# +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"+ (now it's accepted to pass the file contents instead, both must work).
|
2528
|
+
# +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"]+ (now it's accepted to pass the file contents instead, both must work).
|
2526
2529
|
# +output_exception+:: [Bool] output exceptions even if they are admitted?
|
2527
2530
|
#
|
2528
2531
|
# @return [OpenSSL::SSL::SSLServer] returns an ssl server, which can be used to accept connections.
|
@@ -2544,6 +2547,18 @@ require '#{gem_name}'
|
|
2544
2547
|
output_exception.nne || admit_plain.negate_me
|
2545
2548
|
)
|
2546
2549
|
debug && (stderr.puts "#{__method__} starting")
|
2550
|
+
# openssl functions want contents, not filenames:
|
2551
|
+
extra_cert_pem_files = extra_cert_pem_files
|
2552
|
+
.map! { |extra_cert_pem_file|
|
2553
|
+
file_read [
|
2554
|
+
extra_cert_pem_file,
|
2555
|
+
nil,
|
2556
|
+
nil,
|
2557
|
+
extra_cert_pem_file
|
2558
|
+
]
|
2559
|
+
}
|
2560
|
+
cert_pem_file = file_read [cert_pem_file, nil, nil, cert_pem_file]
|
2561
|
+
priv_pemfile = file_read [priv_pemfile, nil, nil, priv_pemfile]
|
2547
2562
|
|
2548
2563
|
require 'socket'
|
2549
2564
|
plain_server = TCPServer.new ip_addr, listening_port
|
@@ -2551,13 +2566,13 @@ require '#{gem_name}'
|
|
2551
2566
|
require 'openssl'
|
2552
2567
|
ssl_context = OpenSSL::SSL::SSLContext.new
|
2553
2568
|
ssl_context.extra_chain_cert =
|
2569
|
+
# TODO: extra_cert_pem_files could also accept strings instead
|
2554
2570
|
extra_cert_pem_files
|
2555
|
-
.map(&File.method(:read))
|
2556
2571
|
.map(&OpenSSL::X509::Certificate.method(:new))
|
2557
2572
|
ssl_context.cert = OpenSSL::X509::Certificate
|
2558
|
-
.new
|
2573
|
+
.new cert_pem_file
|
2559
2574
|
ssl_context.key = OpenSSL::PKey::RSA
|
2560
|
-
.new
|
2575
|
+
.new priv_pemfile
|
2561
2576
|
ssl_server = OpenSSL::SSL::SSLServer
|
2562
2577
|
.new plain_server, ssl_context
|
2563
2578
|
ssl_server
|
@@ -2735,6 +2750,13 @@ require '#{gem_name}'
|
|
2735
2750
|
end
|
2736
2751
|
|
2737
2752
|
|
2753
|
+
# generates a hash string based on current time
|
2754
|
+
# @return [String] +Time.now.hash.abs.to_s+
|
2755
|
+
def time_now_hash *args
|
2756
|
+
Time.now.hash.abs.to_s
|
2757
|
+
end
|
2758
|
+
|
2759
|
+
|
2738
2760
|
# returns a sample self signed certificate-private key pair
|
2739
2761
|
# that once was created with the command (no password, no
|
2740
2762
|
# expire date):
|
@@ -2782,6 +2804,61 @@ n8mFEtUKobsK
|
|
2782
2804
|
end
|
2783
2805
|
|
2784
2806
|
|
2807
|
+
# has the same functionality as
|
2808
|
+
# #ssl_sample_self_signed_cert.
|
2809
|
+
# this one is left as an example on how
|
2810
|
+
# safely place a certificate/private key
|
2811
|
+
# pair inside this code, instead of leaving
|
2812
|
+
# it in plain or somewhere in your filesystem.
|
2813
|
+
# @param [splat] +args+::, an splat whose elements are expected to be:
|
2814
|
+
# +reserved+:: [splat] reserved for future use
|
2815
|
+
# @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)
|
2816
|
+
def ssl_sample_self_signed_cert_encrypted *args
|
2817
|
+
password = "onlyNSAknows"
|
2818
|
+
# generated with:
|
2819
|
+
# test__enc_dec_interactive [
|
2820
|
+
# ssl_sample_self_signed_cert[0],
|
2821
|
+
# password,
|
2822
|
+
# ]:
|
2823
|
+
self_signed_certificate = dec_interactive [
|
2824
|
+
"owdfr76MvIhPb05PLsPiTw==\n",
|
2825
|
+
"R1QSJSUmfXVB4ET2r5C2MN3MZC75V9Pi7nWl8+lTZ363IJOYK4/DJkKL0Y58\nMo8fp1mvoq0fjhCSdHqld6IMWxFXW3kzXGyuVScfbRbvYV83AAhmq+HTscUE\nYJLsfnUqTzGKN/AB/Kr1x3kIsZsb9oNSQMk3dFHV89AM9Z1d30ZMgtW8mn/c\nTHmxsLaFgKvg8bT9t+ERBr85bmJuphkDBlAc4hP2KS/xTFeKB1QL/lJ/oF9j\ncUmb5uWdmZ0REzLyYu9F1MfHv0lwENi+oJYW50lo7DUTYHnyKxYRo+rlUsDF\n0nyS4wcPQVxvY1vDrC34pFdMtcXLQTzzbAiyJx73fT7WfY40MNNKRZfz/zlG\nl/d4ILNlW43/fVnOwg4yZ1tGT1PovrDs1c8Mxu7zm0QCT7+Dp+nN0zes5K8A\n2aYIsR7Nvm+3OeKrRf2JXHv8J/10NEcPfuYocmitlzrr6yM3+4xMXM94Zt/7\n4+vONht+xOhOxUmJufC4HNOmqszX1480dL96qfhc9zXlvxpbD4DGkgU0AR17\nt1C6XNqI0jQxxDMQa0jn0HsX5C9dmtqunLIz8ZkgfSNJbsOtVYVS11YuXk+k\nbEdVimP6DT1x0KZ+UxpxOFJcuvtM6eBe3aMWRjlIf/xjobJ2GP9OlDq1hPJe\n+zz1lhUxobFZiqSIrVbYz8u6ZuvVSEa8NfQJ+GpE1poExzBAsM5RjSMWK0Yr\nLnasLNQwJkYoDlmZBNOX30pCaZPmLl9xLaJphIeHOcmNL0e209hST4H5s1oZ\np/k+sk/jgqtc6jVBeMVwSEDHLl4F4hiNHqeqW72bim7XlkbVjaZ8Q66hUCK/\nKBlJ9YH4QCm3zN4ZQtoTOwu7G8+GeO46ahShzE9+6uoj8DCN31zcbDA5sKgJ\nc6SkA1KG83cDq2rP9zKAMn8V1O/NMnV/09gqPiowl/60CVuepkpNmVehhBVi\noamQ5r1g2l/PaUr7hmwygLBjnMHYD2eu5M0gMLYtZxCQSiXTxryp8Xd7vBzs\n0oWO2km/RjVedhxIBMGxcL2O17lWvumcr8AQYOuuiciPqNj0p/KxDYUHvIqx\nW3vPHknUzug5gSwfYZF7t5HCAc8dyRyC/b5M7Mvl9OsWdRPpcv25Dr+x/i/r\nrRMyvBLd8cujRh532fuyDZVL8NwPqwkKoBSU/+hkSOfW6WEdwYWp8xHDFmrQ\nD/YTNSSVPhGNSxR4I/niEksgH43zp5MdowcVuVsIxQBI/ExGcloRJ3hVa1I=\n",
|
2826
|
+
"IxDTD59cryQjCnFpYQTudw==\n",
|
2827
|
+
"MjAwMDA=\n",
|
2828
|
+
password,
|
2829
|
+
]
|
2830
|
+
# generated with:
|
2831
|
+
# test__enc_dec_interactive [
|
2832
|
+
# ssl_sample_self_signed_cert[1],
|
2833
|
+
# "onlyNSAknows",
|
2834
|
+
# ]
|
2835
|
+
private_key = dec_interactive [
|
2836
|
+
"mxoZrTsIelpVmTAdSMQJaw==\n",
|
2837
|
+
"ebsMBtAoESJAOrmffbRsNdjv3FUqyTetrKlw6WGCNLre8uChpt38ZRmi1XAr\nab2PxiNyz7OJ8PWwCnd/TjIOhvid3Zt7LbqUpR2ixRmVf/mEFoWrdwdXnOMz\nzQErlSok1dY2cAvGqBihP26yC9N4IGJU5Jrt4wivahnnvWZoC1gvsEZVPC+Q\nxLF69gu8fn4gUgFvzpjuhgcCXk6QyhW916pZxJrtwBRMEQWu9dGEcRqSPqNt\nLfw6cXyGHDNV1320Je2BRjzMrhIfiwkv88oWEjnHcbOzboxhGdvYG8oYNMgQ\nf9qouABXlQyOEnBIFfl2lKoJaizERs1ShsdNCAcyZZPgNdxWNawdcF3AawYh\nqlX+uOlxCsWQLV3AaSDPy9mDthF3IuMLLe/BlY3gkGLCvD4szZIsQhk6047+\n9euOuJxxu8X3r8TZDHQK9esm5O6YeNFIlGko6PXA2OwcdUWO9Umwr7Lu8Mgk\n/yldW0G/6dMZ6qKSSSLTvEnzZChz91GabcntxT2TrOR2b1zHJhfOUUxcHxWe\nkuqZZ6GmGFIPju22cCsstXDZ0Q1J19VnGBsrySR0AHDxS3sLgeihf8SjP1bn\n3B1nRR+1gHyKPthKiuzibJj+j6xcIgYBynyaNIeT0Wfcf7WXyBTZ+Idd7Z+R\nkiy9jnZPqCIEE5aebuVvAUXksPE2OvEgsCIiLSEylXXrHEdcEnfra7wvo0qb\n1G/vRNlOIYJiOsKLOqcg6KZVJ+QHHYPrir33g4N02Q64WEw4/eIzR5o4MV9c\n7tho/VLQBE1T3z8HPlhe8XOXvVIDJ/cDVJhTre6KbKBsA+Ow47Z1uNXAchAO\n2bwl1sN1iH+SNBsEjRiXpjbrk95I/H66+LZoz85kRBcoQIhfXU97qbskBUwX\nK//3HdYluo/xx5QSVNqQUzybQnRdNV7gy6xNIgpot9ZtPB2K00HulWW1dnRQ\nBMCWb5h3eUob826icleZ/bEFfcfY8FjNTh9zhyWra3wJOTGS4zhmnlfhBRFZ\njRUcKGX/zgfIrCKXum+2m7Cku3bez+mKpEMRWIBPweGzjq3DSdtY+qlKOgeV\nBxOOh0QoMw1kzRfqF0D0Nqn785lvcXjH28v1efHf6SgFrOXjFNl0ihXXxhMG\nivsoIGIblspGIddR6wbarq1L8xMBTCAorNo0OrWPYACz4ek2CmQUuLhwiNx/\nWsFmaElfdtNL/WM06D5zehAYnCfg02zVr4bIgrHkFaq+jsI+u7/3GhtAmnAC\nkUT9CQvGNXwki3jIHOJQL1X8vLA2T25lg9I7wU4EXA==\n",
|
2838
|
+
"IBBcvvM2/h7bW+tBcBbXeQ==\n",
|
2839
|
+
"MjAwMDA=\n",
|
2840
|
+
password,
|
2841
|
+
]
|
2842
|
+
[self_signed_certificate, private_key]
|
2843
|
+
end
|
2844
|
+
|
2845
|
+
|
2846
|
+
# test for ssl_sample_self_signed_cert_encrypted
|
2847
|
+
def test_enc_dec_interactive__ssl_sample_self_signed_cert args=ARGV
|
2848
|
+
expectation = {
|
2849
|
+
:self_signed_certificate => ssl_sample_self_signed_cert[0],
|
2850
|
+
:private_key => ssl_sample_self_signed_cert[1],
|
2851
|
+
}
|
2852
|
+
actual = {
|
2853
|
+
:self_signed_certificate => ssl_sample_self_signed_cert_encrypted[0],
|
2854
|
+
:private_key => ssl_sample_self_signed_cert_encrypted[1],
|
2855
|
+
}
|
2856
|
+
judgement = actual.keys.map {|test_case|
|
2857
|
+
[expectation[test_case], actual[test_case] , test_case]
|
2858
|
+
}.map(&method("expect_equal")).all?
|
2859
|
+
end
|
2860
|
+
|
2861
|
+
|
2785
2862
|
# test for tcp_ssl_server (call #io_transform with
|
2786
2863
|
# a function that processes an http request and returns
|
2787
2864
|
# an http_response, by default #http_OK_response)
|
@@ -2794,7 +2871,7 @@ n8mFEtUKobsK
|
|
2794
2871
|
# +openssl req -x509 -nodes -days 365 -newkey rsa:1024 -keyout pkey.pem -out cert.crt+
|
2795
2872
|
# but if the files don't exist, they will be created
|
2796
2873
|
# with a sample self signed certificate.
|
2797
|
-
def
|
2874
|
+
def test__tcp_ssl_server__io_transform args = ARGV
|
2798
2875
|
http_processing_method,
|
2799
2876
|
http_processing_method_args,
|
2800
2877
|
http_server_port,
|
@@ -2802,17 +2879,17 @@ n8mFEtUKobsK
|
|
2802
2879
|
priv_pemfile,
|
2803
2880
|
cert_pem_file,
|
2804
2881
|
extra_cert_pem_files,
|
2882
|
+
ssl_cert_pkey_chain_method,
|
2805
2883
|
reserved = args
|
2806
2884
|
http_processing_method ||= http_processing_method.nne :http_OK_response
|
2807
2885
|
http_processing_method_args ||= http_processing_method_args.nne []
|
2808
2886
|
http_server_port ||= http_server_port.nne 8003
|
2809
2887
|
http_ip_addr ||= http_ip_addr.nne "0"
|
2810
|
-
|
2811
|
-
|
2812
|
-
|
2813
|
-
|
2814
|
-
|
2815
|
-
extra_cert_pem_files ||= extra_cert_pem_files.nne
|
2888
|
+
ssl_cert_pkey_chain_method ||=
|
2889
|
+
ssl_cert_pkey_chain_method.nne :ssl_sample_self_signed_cert_encrypted
|
2890
|
+
priv_pemfile ||= priv_pemfile.nne (send ssl_cert_pkey_chain_method)[1]
|
2891
|
+
cert_pem_file ||= cert_pem_file.nne (send ssl_cert_pkey_chain_method)[0]
|
2892
|
+
extra_cert_pem_files ||= extra_cert_pem_files.nne (send ssl_cert_pkey_chain_method)[2]
|
2816
2893
|
thread = tcp_ssl_server [
|
2817
2894
|
http_server_port,
|
2818
2895
|
http_ip_addr,
|
@@ -2835,6 +2912,89 @@ n8mFEtUKobsK
|
|
2835
2912
|
end
|
2836
2913
|
|
2837
2914
|
|
2915
|
+
# tests #file_read_or_write and #file_read
|
2916
|
+
# specially its +return_on_rescue+ parameter.
|
2917
|
+
# attention that files given by parameter
|
2918
|
+
# will be mercilessly overwritten.
|
2919
|
+
# writes the contents returned by
|
2920
|
+
# #ssl_sample_self_signed_cert
|
2921
|
+
# to 2 files. then reads then.
|
2922
|
+
# after it tries to give the contents of
|
2923
|
+
# those files instead of the filenames.
|
2924
|
+
# the idea behind is that, no matter if
|
2925
|
+
# contents or filename were given, it
|
2926
|
+
# should always return the contents of
|
2927
|
+
# the file.
|
2928
|
+
def test__file_read__return_on_rescue args=ARGV
|
2929
|
+
priv_pemfile, cert_pem_file = args
|
2930
|
+
priv_pemfile ||= priv_pemfile.nne "/tmp/pkey.pem"
|
2931
|
+
cert_pem_file ||= cert_pem_file.nne "/tmp/cert.crt"
|
2932
|
+
runef {
|
2933
|
+
File.delete priv_pemfile
|
2934
|
+
File.delete cert_pem_file
|
2935
|
+
}
|
2936
|
+
cert_contents, pkey_contents = ssl_sample_self_signed_cert
|
2937
|
+
# asserting that file_read_or_write is correct
|
2938
|
+
read_or_write_cert_contents = file_read_or_write cert_pem_file, cert_contents
|
2939
|
+
read_or_write_pkey_contents = file_read_or_write priv_pemfile, pkey_contents
|
2940
|
+
file_dot_read_cert_contents = File.read cert_pem_file
|
2941
|
+
file_dot_read_pkey_contents = File.read priv_pemfile
|
2942
|
+
# files exist case (will return the contents of 1st parameter filename):
|
2943
|
+
existing_cert_contents = file_read [cert_pem_file, nil, nil, cert_pem_file]
|
2944
|
+
existing_pkey_contents = file_read [priv_pemfile, nil, nil, priv_pemfile ]
|
2945
|
+
# files don't exist case (will return the 4th parameter):
|
2946
|
+
rescue_cert_contents = file_read [cert_contents, nil, nil, cert_contents]
|
2947
|
+
rescue_pkey_contents = file_read [pkey_contents, nil, nil, pkey_contents]
|
2948
|
+
judgement =
|
2949
|
+
[
|
2950
|
+
[read_or_write_cert_contents, cert_contents, "read_or_write_cert_contents"],
|
2951
|
+
[read_or_write_pkey_contents, pkey_contents, "read_or_write_pkey_contents"],
|
2952
|
+
[file_dot_read_cert_contents, cert_contents, "file_dot_read_cert_contents"],
|
2953
|
+
[file_dot_read_pkey_contents, pkey_contents, "file_dot_read_pkey_contents"],
|
2954
|
+
[existing_cert_contents, cert_contents, "existing_cert_contents"],
|
2955
|
+
[existing_pkey_contents, pkey_contents, "existing_pkey_contents"],
|
2956
|
+
[rescue_cert_contents, cert_contents, "rescue_cert_contents"],
|
2957
|
+
[rescue_pkey_contents, pkey_contents, "rescue_pkey_contents"],
|
2958
|
+
].map(&method("expect_equal")).all?
|
2959
|
+
end
|
2960
|
+
|
2961
|
+
|
2962
|
+
# test for tcp_ssl_server (call #io_transform with
|
2963
|
+
# a function that processes an http request and returns
|
2964
|
+
# an http_response, by default #http_OK_response)
|
2965
|
+
# just like #test__tcp_ssl_server__non_ssl,
|
2966
|
+
# calling directly #tcp_ssl_server, but making
|
2967
|
+
# mandatory the server to be ssl one.
|
2968
|
+
# requires, by default that the certificate and its
|
2969
|
+
# private key are found in the current dir, which
|
2970
|
+
# can be achieved with:
|
2971
|
+
# +openssl req -x509 -nodes -days 365 -newkey rsa:1024 -keyout pkey.pem -out cert.crt+
|
2972
|
+
# but if the files don't exist, they will be created
|
2973
|
+
# with a sample self signed certificate.
|
2974
|
+
def test__tcp_ssl_server__ssl_self_signed args = ARGV
|
2975
|
+
http_processing_method,
|
2976
|
+
http_processing_method_args,
|
2977
|
+
http_server_port,
|
2978
|
+
http_ip_addr,
|
2979
|
+
priv_pemfile,
|
2980
|
+
cert_pem_file,
|
2981
|
+
extra_cert_pem_files,
|
2982
|
+
reserved = args
|
2983
|
+
ssl_cert_pkey_chain_method = :ssl_sample_self_signed_cert_encrypted
|
2984
|
+
test__tcp_ssl_server__io_transform [
|
2985
|
+
http_processing_method,
|
2986
|
+
http_processing_method_args,
|
2987
|
+
http_server_port,
|
2988
|
+
http_ip_addr,
|
2989
|
+
priv_pemfile,
|
2990
|
+
cert_pem_file,
|
2991
|
+
extra_cert_pem_files,
|
2992
|
+
ssl_cert_pkey_chain_method,
|
2993
|
+
]
|
2994
|
+
true
|
2995
|
+
end
|
2996
|
+
|
2997
|
+
|
2838
2998
|
# test for Object::nne
|
2839
2999
|
def test__object_nne args = ARGV
|
2840
3000
|
string_neutral = ""
|