svengali 0.2.7.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/LICENSE +20 -0
- data/README +0 -0
- data/README.rdoc +17 -0
- data/Rakefile +47 -0
- data/VERSION +1 -0
- data/api_document020_en.pdf +0 -0
- data/api_document020_ja.pdf +0 -0
- data/api_document_en.pptx +0 -0
- data/api_document_ja.pptx +0 -0
- data/lib/svengali.rb +2 -0
- data/lib/svengali/config.rb +78 -0
- data/lib/svengali/ext_string.rb +55 -0
- data/lib/svengali/ext_string/command.yml +6 -0
- data/lib/svengali/ext_string/path.yml +6 -0
- data/lib/svengali/file_io.rb +106 -0
- data/lib/svengali/machine.rb +123 -0
- data/lib/svengali/platforms/debian.rb +5 -0
- data/lib/svengali/platforms/default.rb +4 -0
- data/lib/svengali/plugins/eucalyptus.rb +339 -0
- data/lib/svengali/plugins/machine_config.rb +126 -0
- data/lib/svengali/plugins/package.rb +7 -0
- data/lib/svengali/ssh.rb +106 -0
- data/lib/svengali/svengali.rb +19 -0
- data/lib/svengali/util.rb +117 -0
- data/rdoc/classes/CLibIPAddr.html +230 -0
- data/rdoc/classes/Cloud.html +506 -0
- data/rdoc/classes/Config.html +151 -0
- data/rdoc/classes/Config/ConfigFile.html +319 -0
- data/rdoc/classes/ExtStr.html +209 -0
- data/rdoc/classes/ExtStrAccessor.html +183 -0
- data/rdoc/classes/FileIO.html +415 -0
- data/rdoc/classes/Machine.html +771 -0
- data/rdoc/classes/MachineMaster.html +117 -0
- data/rdoc/classes/Platform.html +121 -0
- data/rdoc/classes/SSH.html +315 -0
- data/rdoc/created.rid +1 -0
- data/rdoc/files/README.html +101 -0
- data/rdoc/files/README_rdoc.html +133 -0
- data/rdoc/files/lib/svengali/config_rb.html +114 -0
- data/rdoc/files/lib/svengali/ext_string_rb.html +108 -0
- data/rdoc/files/lib/svengali/file_io_rb.html +115 -0
- data/rdoc/files/lib/svengali/machine_rb.html +108 -0
- data/rdoc/files/lib/svengali/platforms/debian_rb.html +107 -0
- data/rdoc/files/lib/svengali/platforms/default_rb.html +107 -0
- data/rdoc/files/lib/svengali/plugins/eucalyptus_rb.html +389 -0
- data/rdoc/files/lib/svengali/plugins/machine_config_rb.html +101 -0
- data/rdoc/files/lib/svengali/plugins/package_rb.html +101 -0
- data/rdoc/files/lib/svengali/ssh_rb.html +110 -0
- data/rdoc/files/lib/svengali/svengali_rb.html +125 -0
- data/rdoc/files/lib/svengali/util_rb.html +439 -0
- data/rdoc/files/lib/svengali_rb.html +108 -0
- data/rdoc/fr_class_index.html +37 -0
- data/rdoc/fr_file_index.html +41 -0
- data/rdoc/fr_method_index.html +100 -0
- data/rdoc/index.html +26 -0
- data/rdoc/rdoc-style.css +208 -0
- data/spec/spec.opts +1 -0
- data/spec/spec_helper.rb +9 -0
- data/spec/svengali_spec.rb +7 -0
- data/svengali.gemspec +113 -0
- data/svengali_sample.rb +43 -0
- data/test/scenario.sh +3 -0
- metadata +179 -0
data/lib/svengali/ssh.rb
ADDED
@@ -0,0 +1,106 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
gem 'net-ssh'
|
3
|
+
require 'net/ssh'
|
4
|
+
require 'timeout'
|
5
|
+
|
6
|
+
class SSH
|
7
|
+
@host
|
8
|
+
@user_name
|
9
|
+
@password
|
10
|
+
@passphrase
|
11
|
+
@private_key_path
|
12
|
+
@session
|
13
|
+
@shell
|
14
|
+
@sftp_session
|
15
|
+
|
16
|
+
attr_reader :sftp_session
|
17
|
+
attr_reader :session
|
18
|
+
|
19
|
+
def initialize(host,user_name=nil,password=nil,private_key_path=nil)
|
20
|
+
if user_name && password && private_key_path
|
21
|
+
@user_name = user_name
|
22
|
+
@passphrase = password
|
23
|
+
@private_key_path = private_key_path
|
24
|
+
elsif user_name || password
|
25
|
+
@user_name = user_name
|
26
|
+
@password = password
|
27
|
+
initialize(host)
|
28
|
+
else #substitute of constructor which has no argument
|
29
|
+
@host = host
|
30
|
+
@terminator = ""
|
31
|
+
|
32
|
+
wait_until_ssh_connectable(CLibIPAddr.new(host))
|
33
|
+
|
34
|
+
if @user_name && @password && @private_key_path #if initialized with private_key_path, user_name and password
|
35
|
+
debug_p "Try Net::SSH.start()!"
|
36
|
+
@session = Net::SSH.start(@host, @user_name,:passphrase => @passphrase, :keys => [ @private_key_path ] )
|
37
|
+
elsif @user_name && @password #if initialized with user_name and password
|
38
|
+
debug_p "Try Net::SSH.start()!"
|
39
|
+
@session = Net::SSH.start(@host, @user_name,:password => @password)
|
40
|
+
elsif @user_name #if initialized with user_name
|
41
|
+
debug_p "Try Net::SSH.start()!"
|
42
|
+
@session = Net::SSH.start(@host, @user_name)
|
43
|
+
end
|
44
|
+
debug_p "Net::SSH.start finished."
|
45
|
+
@sftp_session = @session.sftp.connect()
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
def close
|
50
|
+
@session.close()
|
51
|
+
end
|
52
|
+
|
53
|
+
#exec and return string of stdout
|
54
|
+
#this method blocks until remote call is finished
|
55
|
+
#if execution is timeouted, this func returns nil
|
56
|
+
|
57
|
+
# return value : String of stdout or stderr
|
58
|
+
def exec!(command_str,time_out = nil)
|
59
|
+
debug_p "exec! -> \"#{command_str}\""
|
60
|
+
|
61
|
+
begin
|
62
|
+
timeout(time_out) do
|
63
|
+
return_val = ""
|
64
|
+
@session.exec!(command_str) { |ch, stream, data|
|
65
|
+
if stream == :stdout
|
66
|
+
return_val += data
|
67
|
+
elsif stream == :stderr
|
68
|
+
return_val += data
|
69
|
+
end
|
70
|
+
}
|
71
|
+
return return_val
|
72
|
+
end
|
73
|
+
rescue TimeoutError
|
74
|
+
return nil
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
# exec and return string of stdout
|
79
|
+
# this method blocks until remote call is finished
|
80
|
+
|
81
|
+
# return value : nothing
|
82
|
+
def exec(command_str)
|
83
|
+
debug_p "exec -> \"#{command_str}\""
|
84
|
+
|
85
|
+
@session.exec(command_str)
|
86
|
+
end
|
87
|
+
|
88
|
+
def wait_until_ssh_connectable(host)
|
89
|
+
# waits until ensure that ssh connection can be accept
|
90
|
+
while(is_ssh_connectable(host) == false)
|
91
|
+
sleep(1)
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
# ipaddr -> CLibIPAddr: address of target machine
|
96
|
+
def is_ssh_connectable(ipaddr)
|
97
|
+
begin
|
98
|
+
s = TCPSocket.open(ipaddr.to_s,22)
|
99
|
+
s.close()
|
100
|
+
return true
|
101
|
+
rescue
|
102
|
+
return false
|
103
|
+
end
|
104
|
+
end
|
105
|
+
private "is_ssh_connectable"
|
106
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
#main routine of svengali
|
2
|
+
|
3
|
+
# slash of tails is to avoid a baffling bug
|
4
|
+
LIBNAME = "svengali/"
|
5
|
+
|
6
|
+
require "#{LIBNAME}/file_io"
|
7
|
+
require "#{LIBNAME}/machine"
|
8
|
+
require "#{LIBNAME}/ssh"
|
9
|
+
require "#{LIBNAME}/util"
|
10
|
+
|
11
|
+
#load the defualt platform in the meantime
|
12
|
+
require "#{LIBNAME}/platforms/default"
|
13
|
+
|
14
|
+
#load default plugins
|
15
|
+
load_plugin("machine_config")
|
16
|
+
load_plugin("package")
|
17
|
+
|
18
|
+
#all global variables defined on this library is here
|
19
|
+
$platform_name = "default"
|
@@ -0,0 +1,117 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
require "socket"
|
3
|
+
|
4
|
+
#module CloudUtil
|
5
|
+
class CLibIPAddr
|
6
|
+
@ipaddr
|
7
|
+
|
8
|
+
def initialize(ipaddr_str)
|
9
|
+
@ipaddr = ipaddr_str
|
10
|
+
end
|
11
|
+
|
12
|
+
def inc!
|
13
|
+
splited_arr = @ipaddr.split(".")
|
14
|
+
last_octet = splited_arr[3].to_i
|
15
|
+
#remove last octet
|
16
|
+
splited_arr.pop()
|
17
|
+
@ipaddr = splited_arr.join(".") + "." + (last_octet+1).to_s
|
18
|
+
end
|
19
|
+
|
20
|
+
def to_s
|
21
|
+
return @ipaddr
|
22
|
+
end
|
23
|
+
|
24
|
+
def dup()
|
25
|
+
return CLibIPAddr.new(@ipaddr)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
$output_debug_print = false
|
30
|
+
|
31
|
+
def stop_debug_print()
|
32
|
+
$output_debug_print = false
|
33
|
+
end
|
34
|
+
|
35
|
+
def debug_p(str = "")
|
36
|
+
if $output_debug_print
|
37
|
+
puts "[DEBUG #{caller(1)[0]}] #{str}"
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
def not_inp()
|
42
|
+
debug_p(caller(1)[0] + " -> Not implemented yet.")
|
43
|
+
end
|
44
|
+
|
45
|
+
def lazy_inp()
|
46
|
+
debug_p(caller(1)[0] + " -> Lazily implemented. Here should be fixed if you have time.")
|
47
|
+
end
|
48
|
+
|
49
|
+
def not_tested()
|
50
|
+
debug_p(caller(1)[0] + " -> Not tested yet.")
|
51
|
+
end
|
52
|
+
|
53
|
+
def load_plugin(plugin_name_str)
|
54
|
+
# open( File::dirname(__FILE__) + "/plugin/" + plugin_name_str + ".rb"){ |file|
|
55
|
+
# contents = file.read()
|
56
|
+
# contents = "class Machine\n" + contents + "\nend"
|
57
|
+
# eval(contents)
|
58
|
+
# }
|
59
|
+
require "#{LIBNAME}/plugins/" + plugin_name_str
|
60
|
+
end
|
61
|
+
|
62
|
+
# change platform "default" to *platform_name_str*
|
63
|
+
# "default" was specified on svengali.rb on ahead
|
64
|
+
def change_platform(platform_name_str)
|
65
|
+
require "#{LIBNAME}/platforms/" + platform_name_str
|
66
|
+
$platform_name = platform_name_str
|
67
|
+
end
|
68
|
+
|
69
|
+
def err_message_and_exit(str)
|
70
|
+
debug_p str
|
71
|
+
debug_p "I'm exiting!"
|
72
|
+
|
73
|
+
exit()
|
74
|
+
end
|
75
|
+
|
76
|
+
# **Attention** this method passes nil values
|
77
|
+
def check_has_keys(params_hash,array_of_symbols)
|
78
|
+
array_of_symbols.each{ |symbol|
|
79
|
+
unless params_hash.has_key?(symbol)
|
80
|
+
err_message_and_exit("please specify a value of :" + symbol.to_s() + "!")
|
81
|
+
end
|
82
|
+
}
|
83
|
+
end
|
84
|
+
|
85
|
+
# ipaddr -> ClibIPAddr : destination IP address
|
86
|
+
# return -> boolean
|
87
|
+
#
|
88
|
+
# This method returns at most 3sec after
|
89
|
+
def is_exist_by_ping(ipaddr)
|
90
|
+
# this execution returns at most 3sec after
|
91
|
+
`ping #{ipaddr.to_s} -c 1 -w 3`
|
92
|
+
result = ( $? == 0 ) ? true : false
|
93
|
+
return result
|
94
|
+
end
|
95
|
+
|
96
|
+
# ipaddr_range_str is like below
|
97
|
+
# "192.168.1.100-200"
|
98
|
+
#
|
99
|
+
# return -> hash : { string of ipaddr => true, ........ , string of ipaddr => true}
|
100
|
+
def find_machines_on_range_by_ping(ipaddr_range_str)
|
101
|
+
octets_arr = ipaddr_range_str.split(".")
|
102
|
+
splited_last_octet = octets_arr[3].split("-")
|
103
|
+
|
104
|
+
alive_hash = Hash.new()
|
105
|
+
for last_octet in splited_last_octet[0].to_i .. splited_last_octet[1].to_i
|
106
|
+
t = Thread.new do
|
107
|
+
dest_ip_str = octets_arr[0] + "." + octets_arr[1] + "." + octets_arr[2] + "." + last_octet.to_s()
|
108
|
+
if is_exist_by_ping(CLibIPAddr.new(dest_ip_str))
|
109
|
+
alive_hash[dest_ip_str] = true
|
110
|
+
end
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
t.join
|
115
|
+
|
116
|
+
return alive_hash
|
117
|
+
end
|
@@ -0,0 +1,230 @@
|
|
1
|
+
<?xml version="1.0" encoding="iso-8859-1"?>
|
2
|
+
<!DOCTYPE html
|
3
|
+
PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
|
4
|
+
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
5
|
+
|
6
|
+
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
|
7
|
+
<head>
|
8
|
+
<title>Class: CLibIPAddr</title>
|
9
|
+
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
|
10
|
+
<meta http-equiv="Content-Script-Type" content="text/javascript" />
|
11
|
+
<link rel="stylesheet" href=".././rdoc-style.css" type="text/css" media="screen" />
|
12
|
+
<script type="text/javascript">
|
13
|
+
// <![CDATA[
|
14
|
+
|
15
|
+
function popupCode( url ) {
|
16
|
+
window.open(url, "Code", "resizable=yes,scrollbars=yes,toolbar=no,status=no,height=150,width=400")
|
17
|
+
}
|
18
|
+
|
19
|
+
function toggleCode( id ) {
|
20
|
+
if ( document.getElementById )
|
21
|
+
elem = document.getElementById( id );
|
22
|
+
else if ( document.all )
|
23
|
+
elem = eval( "document.all." + id );
|
24
|
+
else
|
25
|
+
return false;
|
26
|
+
|
27
|
+
elemStyle = elem.style;
|
28
|
+
|
29
|
+
if ( elemStyle.display != "block" ) {
|
30
|
+
elemStyle.display = "block"
|
31
|
+
} else {
|
32
|
+
elemStyle.display = "none"
|
33
|
+
}
|
34
|
+
|
35
|
+
return true;
|
36
|
+
}
|
37
|
+
|
38
|
+
// Make codeblocks hidden by default
|
39
|
+
document.writeln( "<style type=\"text/css\">div.method-source-code { display: none }</style>" )
|
40
|
+
|
41
|
+
// ]]>
|
42
|
+
</script>
|
43
|
+
|
44
|
+
</head>
|
45
|
+
<body>
|
46
|
+
|
47
|
+
|
48
|
+
|
49
|
+
<div id="classHeader">
|
50
|
+
<table class="header-table">
|
51
|
+
<tr class="top-aligned-row">
|
52
|
+
<td><strong>Class</strong></td>
|
53
|
+
<td class="class-name-in-header">CLibIPAddr</td>
|
54
|
+
</tr>
|
55
|
+
<tr class="top-aligned-row">
|
56
|
+
<td><strong>In:</strong></td>
|
57
|
+
<td>
|
58
|
+
<a href="../files/lib/svengali/util_rb.html">
|
59
|
+
lib/svengali/util.rb
|
60
|
+
</a>
|
61
|
+
<br />
|
62
|
+
</td>
|
63
|
+
</tr>
|
64
|
+
|
65
|
+
<tr class="top-aligned-row">
|
66
|
+
<td><strong>Parent:</strong></td>
|
67
|
+
<td>
|
68
|
+
Object
|
69
|
+
</td>
|
70
|
+
</tr>
|
71
|
+
</table>
|
72
|
+
</div>
|
73
|
+
<!-- banner header -->
|
74
|
+
|
75
|
+
<div id="bodyContent">
|
76
|
+
|
77
|
+
|
78
|
+
|
79
|
+
<div id="contextContent">
|
80
|
+
|
81
|
+
<div id="description">
|
82
|
+
<p>
|
83
|
+
module CloudUtil
|
84
|
+
</p>
|
85
|
+
|
86
|
+
</div>
|
87
|
+
|
88
|
+
|
89
|
+
</div>
|
90
|
+
|
91
|
+
<div id="method-list">
|
92
|
+
<h3 class="section-bar">Methods</h3>
|
93
|
+
|
94
|
+
<div class="name-list">
|
95
|
+
<a href="#M000058">dup</a>
|
96
|
+
<a href="#M000056">inc!</a>
|
97
|
+
<a href="#M000055">new</a>
|
98
|
+
<a href="#M000057">to_s</a>
|
99
|
+
</div>
|
100
|
+
</div>
|
101
|
+
|
102
|
+
</div>
|
103
|
+
|
104
|
+
|
105
|
+
<!-- if includes -->
|
106
|
+
|
107
|
+
<div id="section">
|
108
|
+
|
109
|
+
|
110
|
+
|
111
|
+
|
112
|
+
|
113
|
+
|
114
|
+
|
115
|
+
|
116
|
+
<!-- if method_list -->
|
117
|
+
<div id="methods">
|
118
|
+
<h3 class="section-bar">Public Class methods</h3>
|
119
|
+
|
120
|
+
<div id="method-M000055" class="method-detail">
|
121
|
+
<a name="M000055"></a>
|
122
|
+
|
123
|
+
<div class="method-heading">
|
124
|
+
<a href="#M000055" class="method-signature">
|
125
|
+
<span class="method-name">new</span><span class="method-args">(ipaddr_str)</span>
|
126
|
+
</a>
|
127
|
+
</div>
|
128
|
+
|
129
|
+
<div class="method-description">
|
130
|
+
<p><a class="source-toggle" href="#"
|
131
|
+
onclick="toggleCode('M000055-source');return false;">[Source]</a></p>
|
132
|
+
<div class="method-source-code" id="M000055-source">
|
133
|
+
<pre>
|
134
|
+
<span class="ruby-comment cmt"># File lib/svengali/util.rb, line 8</span>
|
135
|
+
<span class="ruby-keyword kw">def</span> <span class="ruby-identifier">initialize</span>(<span class="ruby-identifier">ipaddr_str</span>)
|
136
|
+
<span class="ruby-ivar">@ipaddr</span> = <span class="ruby-identifier">ipaddr_str</span>
|
137
|
+
<span class="ruby-keyword kw">end</span>
|
138
|
+
</pre>
|
139
|
+
</div>
|
140
|
+
</div>
|
141
|
+
</div>
|
142
|
+
|
143
|
+
<h3 class="section-bar">Public Instance methods</h3>
|
144
|
+
|
145
|
+
<div id="method-M000058" class="method-detail">
|
146
|
+
<a name="M000058"></a>
|
147
|
+
|
148
|
+
<div class="method-heading">
|
149
|
+
<a href="#M000058" class="method-signature">
|
150
|
+
<span class="method-name">dup</span><span class="method-args">()</span>
|
151
|
+
</a>
|
152
|
+
</div>
|
153
|
+
|
154
|
+
<div class="method-description">
|
155
|
+
<p><a class="source-toggle" href="#"
|
156
|
+
onclick="toggleCode('M000058-source');return false;">[Source]</a></p>
|
157
|
+
<div class="method-source-code" id="M000058-source">
|
158
|
+
<pre>
|
159
|
+
<span class="ruby-comment cmt"># File lib/svengali/util.rb, line 24</span>
|
160
|
+
<span class="ruby-keyword kw">def</span> <span class="ruby-identifier">dup</span>()
|
161
|
+
<span class="ruby-keyword kw">return</span> <span class="ruby-constant">CLibIPAddr</span>.<span class="ruby-identifier">new</span>(<span class="ruby-ivar">@ipaddr</span>)
|
162
|
+
<span class="ruby-keyword kw">end</span>
|
163
|
+
</pre>
|
164
|
+
</div>
|
165
|
+
</div>
|
166
|
+
</div>
|
167
|
+
|
168
|
+
<div id="method-M000056" class="method-detail">
|
169
|
+
<a name="M000056"></a>
|
170
|
+
|
171
|
+
<div class="method-heading">
|
172
|
+
<a href="#M000056" class="method-signature">
|
173
|
+
<span class="method-name">inc!</span><span class="method-args">()</span>
|
174
|
+
</a>
|
175
|
+
</div>
|
176
|
+
|
177
|
+
<div class="method-description">
|
178
|
+
<p><a class="source-toggle" href="#"
|
179
|
+
onclick="toggleCode('M000056-source');return false;">[Source]</a></p>
|
180
|
+
<div class="method-source-code" id="M000056-source">
|
181
|
+
<pre>
|
182
|
+
<span class="ruby-comment cmt"># File lib/svengali/util.rb, line 12</span>
|
183
|
+
<span class="ruby-keyword kw">def</span> <span class="ruby-identifier">inc!</span>
|
184
|
+
<span class="ruby-identifier">splited_arr</span> = <span class="ruby-ivar">@ipaddr</span>.<span class="ruby-identifier">split</span>(<span class="ruby-value str">"."</span>)
|
185
|
+
<span class="ruby-identifier">last_octet</span> = <span class="ruby-identifier">splited_arr</span>[<span class="ruby-value">3</span>].<span class="ruby-identifier">to_i</span>
|
186
|
+
<span class="ruby-comment cmt">#remove last octet</span>
|
187
|
+
<span class="ruby-identifier">splited_arr</span>.<span class="ruby-identifier">pop</span>()
|
188
|
+
<span class="ruby-ivar">@ipaddr</span> = <span class="ruby-identifier">splited_arr</span>.<span class="ruby-identifier">join</span>(<span class="ruby-value str">"."</span>) <span class="ruby-operator">+</span> <span class="ruby-value str">"."</span> <span class="ruby-operator">+</span> (<span class="ruby-identifier">last_octet</span><span class="ruby-operator">+</span><span class="ruby-value">1</span>).<span class="ruby-identifier">to_s</span>
|
189
|
+
<span class="ruby-keyword kw">end</span>
|
190
|
+
</pre>
|
191
|
+
</div>
|
192
|
+
</div>
|
193
|
+
</div>
|
194
|
+
|
195
|
+
<div id="method-M000057" class="method-detail">
|
196
|
+
<a name="M000057"></a>
|
197
|
+
|
198
|
+
<div class="method-heading">
|
199
|
+
<a href="#M000057" class="method-signature">
|
200
|
+
<span class="method-name">to_s</span><span class="method-args">()</span>
|
201
|
+
</a>
|
202
|
+
</div>
|
203
|
+
|
204
|
+
<div class="method-description">
|
205
|
+
<p><a class="source-toggle" href="#"
|
206
|
+
onclick="toggleCode('M000057-source');return false;">[Source]</a></p>
|
207
|
+
<div class="method-source-code" id="M000057-source">
|
208
|
+
<pre>
|
209
|
+
<span class="ruby-comment cmt"># File lib/svengali/util.rb, line 20</span>
|
210
|
+
<span class="ruby-keyword kw">def</span> <span class="ruby-identifier">to_s</span>
|
211
|
+
<span class="ruby-keyword kw">return</span> <span class="ruby-ivar">@ipaddr</span>
|
212
|
+
<span class="ruby-keyword kw">end</span>
|
213
|
+
</pre>
|
214
|
+
</div>
|
215
|
+
</div>
|
216
|
+
</div>
|
217
|
+
|
218
|
+
|
219
|
+
</div>
|
220
|
+
|
221
|
+
|
222
|
+
</div>
|
223
|
+
|
224
|
+
|
225
|
+
<div id="validator-badges">
|
226
|
+
<p><small><a href="http://validator.w3.org/check/referer">[Validate]</a></small></p>
|
227
|
+
</div>
|
228
|
+
|
229
|
+
</body>
|
230
|
+
</html>
|