rubyment 0.6.25503334 → 0.6.25504825
Sign up to get free protection for your applications and to get access to all the features.
- 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 = ""
|