net-snmp 0.2.0 → 0.2.1
Sign up to get free protection for your applications and to get access to all the features.
- data/README.rdoc +12 -3
- data/lib/net/snmp/constants.rb +30 -1
- data/lib/net/snmp/mib/node.rb +2 -2
- data/lib/net/snmp/oid.rb +16 -0
- data/lib/net/snmp/pdu.rb +4 -2
- data/lib/net/snmp/session.rb +93 -92
- data/lib/net/snmp/version.rb +1 -1
- data/spec/sync_spec.rb +25 -14
- metadata +3 -3
data/README.rdoc
CHANGED
@@ -12,7 +12,8 @@ It provides classes for sessions, pdus, varbinds, and more.
|
|
12
12
|
* Supports sending of snmpv1 traps and snmpv2 traps/informs using TrapSession
|
13
13
|
* Integrates well with eventmachine, or can be used standalone.
|
14
14
|
* In Ruby 1.9, uses fibers behind the scenes to emulate synchronous calls asynchronously
|
15
|
-
|
15
|
+
* MIB support
|
16
|
+
* Convenience methods such as session.walk, session.get_columns, and session.table
|
16
17
|
|
17
18
|
== USAGE
|
18
19
|
|
@@ -49,7 +50,7 @@ You must call Session.close when you're done with a session to avoid leaking mem
|
|
49
50
|
In the synchronous versions, all session methods raise Net::SNMP:Error on any error. Timeouts raise Net::SNMP::TimeoutError.
|
50
51
|
In the asynchronous versions, the first argument to your callback will be the return status. Possible values include :success, :timeout, and :send_error.
|
51
52
|
If you need the underlying net-snmp session errors, you can call session.errno, session.snmp_err, and session.error_message.
|
52
|
-
|
53
|
+
PDU errors can be retreived with pdu.errstat, pdu.errindex giving the index of the offending varbind. See constants.rb for possible errors.
|
53
54
|
|
54
55
|
== EXAMPLES
|
55
56
|
|
@@ -137,6 +138,13 @@ Net::SNMP::OID objects. For example
|
|
137
138
|
|
138
139
|
For more complex MIB parsing needs, see smi-ffi[http://github.com/mixtli/smi-ffi]
|
139
140
|
|
141
|
+
== EXPERIMENTAL THREAD SUPPORT
|
142
|
+
If you intent to use threads, you should set:
|
143
|
+
|
144
|
+
Net::SNMP.thread_safe = true
|
145
|
+
|
146
|
+
Thread support is experimental and may be dropped. Let me know if you're using this feature.
|
147
|
+
|
140
148
|
== CAVEATS/DISCLAIMER
|
141
149
|
|
142
150
|
THIS GEM COULD CRASH YOUR SYSTEM AND EAT YOUR CHILDREN!
|
@@ -166,7 +174,8 @@ break this gem. Please let me know if you find bugs or missing features. Or be
|
|
166
174
|
* Commit, do not mess with rakefile, version, or history.
|
167
175
|
(if you want to have your own version, that is fine but bump version in a commit by itself I can ignore when I pull)
|
168
176
|
* Send me a pull request. Bonus points for topic branches.
|
177
|
+
* Bug reports including a failing rspec get priority treatment
|
169
178
|
|
170
|
-
== Copyright
|
179
|
+
== Copyright
|
171
180
|
|
172
181
|
Copyright (c) 2010 mixtli. See LICENSE for details.
|
data/lib/net/snmp/constants.rb
CHANGED
@@ -49,7 +49,7 @@ module Net
|
|
49
49
|
# Exception values for SNMPv2 and SNMPv3
|
50
50
|
SNMP_NOSUCHOBJECT = (ASN_CONTEXT | ASN_PRIMITIVE | 0x0)
|
51
51
|
SNMP_NOSUCHINSTANCE = (ASN_CONTEXT | ASN_PRIMITIVE | 0x1)
|
52
|
-
|
52
|
+
SNMP_ENDOFMIBVIEW = (ASN_CONTEXT | ASN_PRIMITIVE | 0x2)
|
53
53
|
|
54
54
|
|
55
55
|
# PDU types
|
@@ -71,6 +71,35 @@ module Net
|
|
71
71
|
NETSNMP_CALLBACK_OP_CONNECT = 4
|
72
72
|
NETSNMP_CALLBACK_OP_DISCONNECT = 5
|
73
73
|
|
74
|
+
|
75
|
+
# Error codes (the value of the field error-status in PDUs)
|
76
|
+
|
77
|
+
# in SNMPv1, SNMPsec, SNMPv2p, SNMPv2c, SNMPv2u, SNMPv2*, and SNMPv3 PDUs
|
78
|
+
SNMP_ERR_NOERROR = (0) # XXX Used only for PDUs?
|
79
|
+
SNMP_ERR_TOOBIG = (1)
|
80
|
+
SNMP_ERR_NOSUCHNAME = (2)
|
81
|
+
SNMP_ERR_BADVALUE = (3)
|
82
|
+
SNMP_ERR_READONLY = (4)
|
83
|
+
SNMP_ERR_GENERR = (5)
|
84
|
+
|
85
|
+
# in SNMPv2p, SNMPv2c, SNMPv2u, SNMPv2*, and SNMPv3 PDUs
|
86
|
+
SNMP_ERR_NOACCESS = (6)
|
87
|
+
SNMP_ERR_WRONGTYPE = (7)
|
88
|
+
SNMP_ERR_WRONGLENGTH = (8)
|
89
|
+
SNMP_ERR_WRONGENCODING = (9)
|
90
|
+
SNMP_ERR_WRONGVALUE = (10)
|
91
|
+
SNMP_ERR_NOCREATION = (11)
|
92
|
+
SNMP_ERR_INCONSISTENTVALUE = (12)
|
93
|
+
SNMP_ERR_RESOURCEUNAVAILABLE = (13)
|
94
|
+
SNMP_ERR_COMMITFAILED = (14)
|
95
|
+
SNMP_ERR_UNDOFAILED = (15)
|
96
|
+
SNMP_ERR_AUTHORIZATIONERROR = (16)
|
97
|
+
SNMP_ERR_NOTWRITABLE = (17)
|
98
|
+
|
99
|
+
# in SNMPv2c, SNMPv2u, SNMPv2*, and SNMPv3 PDUs
|
100
|
+
SNMP_ERR_INCONSISTENTNAME = (18)
|
101
|
+
|
102
|
+
|
74
103
|
# SNMP Errors
|
75
104
|
SNMPERR_SUCCESS = (0)
|
76
105
|
SNMPERR_GENERR = (-1)
|
data/lib/net/snmp/mib/node.rb
CHANGED
@@ -8,7 +8,7 @@ module Net::SNMP
|
|
8
8
|
class << self
|
9
9
|
def get_node(oid)
|
10
10
|
if oid.kind_of?(String)
|
11
|
-
oid =
|
11
|
+
oid = OID.new(oid)
|
12
12
|
end
|
13
13
|
struct = Wrapper.get_tree(oid.pointer, oid.length_pointer.read_int, Wrapper.get_tree_head().pointer)
|
14
14
|
new(struct.pointer)
|
@@ -30,7 +30,7 @@ module Net::SNMP
|
|
30
30
|
|
31
31
|
def oid
|
32
32
|
return @oid if @oid
|
33
|
-
@oid =
|
33
|
+
@oid = OID.new(label)
|
34
34
|
end
|
35
35
|
|
36
36
|
# actually seems like list is linked backward, so this will retrieve the previous oid numerically
|
data/lib/net/snmp/oid.rb
CHANGED
@@ -52,6 +52,22 @@ module Net
|
|
52
52
|
node.label + "." + index
|
53
53
|
end
|
54
54
|
|
55
|
+
def <=>(o)
|
56
|
+
a = self._packed
|
57
|
+
b = o._packed
|
58
|
+
a <=> b
|
59
|
+
end
|
60
|
+
|
61
|
+
def _packed
|
62
|
+
i = self.to_s.dip
|
63
|
+
i.sub!(/^\./,'')
|
64
|
+
i.gsub!(/ /, '.0')
|
65
|
+
i.replace(i.split('.').map(&:to_i).pack('N*'))
|
66
|
+
end
|
67
|
+
|
68
|
+
def parent_of?(o)
|
69
|
+
o.to_s =~ /^#{self.to_s}\./
|
70
|
+
end
|
55
71
|
end
|
56
72
|
end
|
57
73
|
end
|
data/lib/net/snmp/pdu.rb
CHANGED
@@ -82,7 +82,6 @@ module Net
|
|
82
82
|
# * +type+ The data type. Possible values include Net::SNMP::ASN_OCTET_STR, Net::SNMP::ASN_COUNTER, etc. See constants.rb
|
83
83
|
# * +value+ The value of the varbind. default is nil.
|
84
84
|
def add_varbind(options)
|
85
|
-
#puts "adding varbind #{options.inspect}"
|
86
85
|
options[:type] ||= case options[:value]
|
87
86
|
when String
|
88
87
|
Constants::ASN_OCTET_STR
|
@@ -125,7 +124,7 @@ module Net
|
|
125
124
|
end
|
126
125
|
end
|
127
126
|
|
128
|
-
oid = options[:oid].kind_of?(
|
127
|
+
oid = options[:oid].kind_of?(OID) ? options[:oid] : OID.new(options[:oid])
|
129
128
|
var_ptr = Wrapper.snmp_pdu_add_variable(@struct.pointer, oid.pointer, oid.length_pointer.read_int, options[:type], value, value_len)
|
130
129
|
varbind = Varbind.new(var_ptr)
|
131
130
|
#Wrapper.print_varbind(varbind.struct)
|
@@ -142,6 +141,9 @@ module Net
|
|
142
141
|
Wrapper::snmp_errstring(self.errstat)
|
143
142
|
end
|
144
143
|
|
144
|
+
def print_errors
|
145
|
+
puts "errstat = #{self.errstat}, index = #{self.errindex}, message = #{self.error_message}"
|
146
|
+
end
|
145
147
|
# Free the pdu
|
146
148
|
def free
|
147
149
|
Wrapper.snmp_free_pdu(@struct.pointer)
|
data/lib/net/snmp/session.rb
CHANGED
@@ -33,9 +33,7 @@ module Net
|
|
33
33
|
# * +retries+ - snmp retries. default = 5
|
34
34
|
# Returns:
|
35
35
|
# Net::SNMP::Session
|
36
|
-
|
37
36
|
def open(options = {})
|
38
|
-
#puts "building session"
|
39
37
|
session = new(options)
|
40
38
|
if Net::SNMP::thread_safe
|
41
39
|
Net::SNMP::Session.lock.synchronize {
|
@@ -52,7 +50,6 @@ module Net
|
|
52
50
|
end
|
53
51
|
|
54
52
|
def initialize(options = {})
|
55
|
-
#puts "in initialize"
|
56
53
|
@timeout = options[:timeout] || 1
|
57
54
|
@retries = options[:retries] || 5
|
58
55
|
@requests = {}
|
@@ -189,20 +186,17 @@ module Net
|
|
189
186
|
end
|
190
187
|
end
|
191
188
|
|
192
|
-
|
193
|
-
|
194
|
-
|
195
189
|
def default_max_repeaters
|
196
190
|
# We could do something based on transport here. 25 seems safe
|
197
191
|
25
|
198
192
|
end
|
199
193
|
|
200
|
-
|
201
|
-
|
202
194
|
# Raise a NET::SNMP::Error with the session attached
|
203
195
|
def error(msg, options = {})
|
204
196
|
#Wrapper.snmp_sess_perror(msg, @sess.pointer)
|
205
|
-
|
197
|
+
err = Error.new({:session => self}.merge(options))
|
198
|
+
err.print
|
199
|
+
raise err, msg
|
206
200
|
end
|
207
201
|
|
208
202
|
|
@@ -247,6 +241,90 @@ module Net
|
|
247
241
|
alias :poll :select
|
248
242
|
|
249
243
|
|
244
|
+
# Issue repeated getnext requests on each oid passed in until
|
245
|
+
# the result is no longer a child. Returns a hash with the numeric
|
246
|
+
# oid strings as keys.
|
247
|
+
# XXX work in progress. only works synchronously (except with EM + fibers).
|
248
|
+
# Need to do better error checking and use getbulk when avaiable.
|
249
|
+
def walk(oidlist)
|
250
|
+
oidlist = [oidlist] unless oidlist.kind_of?(Array)
|
251
|
+
oidlist = oidlist.map {|o| o.kind_of?(OID) ? o : OID.new(o)}
|
252
|
+
all_results = {}
|
253
|
+
base_list = oidlist
|
254
|
+
while(!oidlist.empty? && pdu = get_next(oidlist))
|
255
|
+
debug "==============================================================="
|
256
|
+
debug "base_list = #{base_list}"
|
257
|
+
prev_base = base_list.dup
|
258
|
+
oidlist = []
|
259
|
+
print_errors
|
260
|
+
pdu.print_errors
|
261
|
+
pdu.varbinds.each_with_index do |vb, i|
|
262
|
+
if prev_base[i].parent_of?(vb.oid) && vb.object_type != Constants::SNMP_ENDOFMIBVIEW
|
263
|
+
# Still in subtree. Store results and add next oid to list
|
264
|
+
debug "adding #{vb.oid} to oidlist"
|
265
|
+
all_results[vb.oid.to_s] = vb.value
|
266
|
+
oidlist << vb.oid
|
267
|
+
else
|
268
|
+
# End of subtree. Don't add to list or results
|
269
|
+
debug "End of subtree"
|
270
|
+
base_list.delete_at(i)
|
271
|
+
debug "not adding #{vb.oid}"
|
272
|
+
end
|
273
|
+
# If get a pdu error, we can only tell the first failing varbind,
|
274
|
+
# So we remove it and resend all the rest
|
275
|
+
if pdu.error? && pdu.errindex == i + 1
|
276
|
+
oidlist.pop # remove the bad oid
|
277
|
+
debug "caught error"
|
278
|
+
if pdu.varbinds.size > i+1
|
279
|
+
# recram rest of oids on list
|
280
|
+
((i+1)..pdu.varbinds.size).each do |j|
|
281
|
+
debug "j = #{j}"
|
282
|
+
debug "adding #{j} = #{prev_list[j]}"
|
283
|
+
oidlist << prev_list[j]
|
284
|
+
end
|
285
|
+
# delete failing oid from base_list
|
286
|
+
base_list.delete_at(i)
|
287
|
+
end
|
288
|
+
break
|
289
|
+
end
|
290
|
+
end
|
291
|
+
end
|
292
|
+
if block_given?
|
293
|
+
yield all_results
|
294
|
+
end
|
295
|
+
all_results
|
296
|
+
end
|
297
|
+
|
298
|
+
|
299
|
+
# Given a list of columns (e.g ['ifIndex', 'ifDescr'], will return a hash with
|
300
|
+
# the indexes as keys and hashes as values.
|
301
|
+
# puts sess.get_columns(['ifIndex', 'ifDescr']).inspect
|
302
|
+
# {'1' => {'ifIndex' => '1', 'ifDescr' => 'lo0'}, '2' => {'ifIndex' => '2', 'ifDescr' => 'en0'}}
|
303
|
+
def columns(columns)
|
304
|
+
columns = columns.map {|c| c.kind_of?(OID) ? c : OID.new(c)}
|
305
|
+
walk_hash = walk(columns)
|
306
|
+
results = {}
|
307
|
+
walk_hash.each do |k, v|
|
308
|
+
oid = OID.new(k)
|
309
|
+
results[oid.index] ||= {}
|
310
|
+
results[oid.index][oid.node.label] = v
|
311
|
+
end
|
312
|
+
if block_given?
|
313
|
+
yield results
|
314
|
+
end
|
315
|
+
results
|
316
|
+
end
|
317
|
+
|
318
|
+
# table('ifEntry'). You must pass the direct parent entry. Calls columns with all
|
319
|
+
# columns in +table_name+
|
320
|
+
def table(table_name, &blk)
|
321
|
+
column_names = MIB::Node.get_node(table_name).children.collect {|c| c.oid }
|
322
|
+
results = columns(column_names)
|
323
|
+
if block_given?
|
324
|
+
yield results
|
325
|
+
end
|
326
|
+
results
|
327
|
+
end
|
250
328
|
|
251
329
|
# Send a PDU
|
252
330
|
# +pdu+ The Net::SNMP::PDU object to send. Usually created by Session.get, Session.getnext, etc.
|
@@ -280,10 +358,9 @@ module Net
|
|
280
358
|
# puts e.message
|
281
359
|
# end
|
282
360
|
def send_pdu(pdu, &callback)
|
283
|
-
#puts "send_pdu #{Fiber.current.inspect}"
|
284
361
|
if block_given?
|
285
362
|
@requests[pdu.reqid] = callback
|
286
|
-
|
363
|
+
debug "calling async_send"
|
287
364
|
if Wrapper.snmp_sess_async_send(@struct, pdu.pointer, sess_callback, nil) == 0
|
288
365
|
error("snmp_get async failed")
|
289
366
|
end
|
@@ -346,11 +423,14 @@ module Net
|
|
346
423
|
get_error
|
347
424
|
@snmp_msg
|
348
425
|
end
|
349
|
-
|
426
|
+
|
427
|
+
def print_errors
|
428
|
+
puts "errno: #{errno}, snmp_err: #{@snmp_err}, message: #{@snmp_msg}"
|
429
|
+
end
|
350
430
|
private
|
351
431
|
def sess_callback
|
352
432
|
@sess_callback ||= FFI::Function.new(:int, [:int, :pointer, :int, :pointer, :pointer]) do |operation, session, reqid, pdu_ptr, magic|
|
353
|
-
|
433
|
+
debug "in callback #{operation.inspect} #{session.inspect}"
|
354
434
|
op = case operation
|
355
435
|
when Constants::NETSNMP_CALLBACK_OP_RECEIVED_MESSAGE
|
356
436
|
:success
|
@@ -386,86 +466,7 @@ module Net
|
|
386
466
|
@snmp_msg = msg_ptr.read_pointer.read_string
|
387
467
|
end
|
388
468
|
|
389
|
-
public
|
390
|
-
# XXX This needs work. Need to use getbulk for speed, guess maxrepeaters, etc..
|
391
|
-
# Also need to figure out how we can tell column names from something like ifTable
|
392
|
-
# instead of ifEntry. Needs to handle errors, there are probably offset problems
|
393
|
-
# in cases of bad data, and various other problems. Also need to add async support.
|
394
|
-
# Maybe return a hash with index as key?
|
395
|
-
def get_table(table_name, options = {})
|
396
|
-
column_names = options[:columns] || MIB::Node.get_node(table_name).children.collect {|c| c.label }
|
397
|
-
results = []
|
398
|
-
|
399
|
-
# repeat_count = if @version.to_s == '1' || options[:no_getbulk]
|
400
|
-
# 1
|
401
|
-
# elsif options[:repeat_count]
|
402
|
-
# options[:repeat_count]
|
403
|
-
# else
|
404
|
-
# (1000 / 36 / (column_names.size + 1)).to_i
|
405
|
-
# end
|
406
|
-
#
|
407
|
-
# res = if @version.to_s != '1' && !options[:no_getbulk]
|
408
|
-
# get_bulk(column_names, :max_repetitions => repeat_count)
|
409
|
-
# else
|
410
|
-
# get_next(column_names)
|
411
|
-
# end
|
412
|
-
|
413
|
-
|
414
|
-
first_result = get_next(column_names)
|
415
|
-
oidlist = []
|
416
|
-
good_column_names = []
|
417
|
-
row = {}
|
418
|
-
|
419
|
-
first_result.varbinds.each_with_index do |vb, idx|
|
420
|
-
oid = vb.oid
|
421
|
-
if oid.label[0..column_names[idx].length - 1] == column_names[idx]
|
422
|
-
oidlist << oid.label
|
423
|
-
good_column_names << column_names[idx]
|
424
|
-
row[column_names[idx]] = vb.value
|
425
|
-
end
|
426
|
-
end
|
427
|
-
results << row
|
428
|
-
|
429
|
-
catch :break_main_loop do
|
430
|
-
while(result = get_next(oidlist))
|
431
|
-
oidlist = []
|
432
|
-
row = {}
|
433
|
-
result.varbinds.each_with_index do |vb, idx|
|
434
|
-
#puts "got #{vb.oid.label} #{vb.value.inspect}, type = #{vb.object_type}"
|
435
|
-
row[good_column_names[idx]] = vb.value
|
436
|
-
oidlist << vb.oid.label
|
437
|
-
if vb.oid.label[0..good_column_names[idx].length - 1] != good_column_names[idx]
|
438
|
-
throw :break_main_loop
|
439
|
-
end
|
440
|
-
end
|
441
|
-
results << row
|
442
|
-
end
|
443
|
-
end
|
444
|
-
results
|
445
|
-
end
|
446
|
-
|
447
469
|
|
448
|
-
# def get_entries_cb(pdu, columns, options)
|
449
|
-
# cache = {}
|
450
|
-
# row_index = nil
|
451
|
-
# varbinds = pdu.varbinds.dup
|
452
|
-
# while(varbinds.size > 0)
|
453
|
-
# row = {}
|
454
|
-
# columns.each do |column|
|
455
|
-
# vb = varbinds.shift
|
456
|
-
# if vb.oid.to_s =~ /#{column.to_s}\.(\d+(:?\.\d+)*)/
|
457
|
-
# index = $1
|
458
|
-
# else
|
459
|
-
# last_entry = true
|
460
|
-
# next
|
461
|
-
# end
|
462
|
-
# row_index = index unless row_index
|
463
|
-
# index_cmp = Net::SNMP.oid_lex_cmp(index, row_index)
|
464
|
-
# if(index_cmp == 0)
|
465
|
-
# end
|
466
|
-
# end
|
467
|
-
# end
|
468
|
-
# end
|
469
470
|
end
|
470
471
|
end
|
471
472
|
end
|
data/lib/net/snmp/version.rb
CHANGED
data/spec/sync_spec.rb
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
|
2
|
+
require 'pp'
|
2
3
|
|
3
4
|
describe "synchronous calls" do
|
4
5
|
# To test sets, you have to have a local snmpd running with write permissions
|
@@ -65,29 +66,39 @@ describe "synchronous calls" do
|
|
65
66
|
end
|
66
67
|
end
|
67
68
|
|
68
|
-
it "get_table should work with multiple columns" do
|
69
|
-
#pending
|
70
|
-
session = Net::SNMP::Session.open(:peername => "localhost", :version => '1')
|
71
|
-
table = session.get_table("ifTable", :columns => ["ifIndex", "ifDescr", "ifName"])
|
72
|
-
table[0]['ifName'].should eql("lo0")
|
73
|
-
table[1]['ifName'].should eql("gif0")
|
74
|
-
end
|
75
|
-
|
76
69
|
it "get_table should work" do
|
77
|
-
pending "not yet implemented"
|
70
|
+
#pending "not yet implemented"
|
78
71
|
session = Net::SNMP::Session.open(:peername => "localhost", :version => '1')
|
79
|
-
table = session.
|
80
|
-
table[
|
81
|
-
table[
|
72
|
+
table = session.table("ifEntry")
|
73
|
+
table['1']['ifIndex'].should eql(1)
|
74
|
+
table['2']['ifIndex'].should eql(2)
|
82
75
|
end
|
83
76
|
|
84
77
|
it "walk should work" do
|
85
|
-
pending "not yet implemented"
|
86
|
-
session = Net::SNMP::Session.open(:peername => 'test.net-snmp.org', :version => 1)
|
78
|
+
#pending "not yet implemented"
|
79
|
+
session = Net::SNMP::Session.open(:peername => 'test.net-snmp.org', :version => 1, :community => 'demopublic')
|
87
80
|
results = session.walk("system")
|
88
81
|
results['1.3.6.1.2.1.1.1.0'].should match(/test.net-snmp.org/)
|
89
82
|
end
|
90
83
|
|
84
|
+
it "walk should work with multiple oids" do
|
85
|
+
Net::SNMP::Session.open(:peername => 'localhost', :version => 1) do |sess|
|
86
|
+
sess.walk(['system', 'ifTable']) do |results|
|
87
|
+
pp results
|
88
|
+
results['1.3.6.1.2.1.1.1.0'].should match(/Darwin/)
|
89
|
+
results['1.3.6.1.2.1.2.2.1.1.2'].should eql(2)
|
90
|
+
results.size.should eql(186)
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
it "get_columns should work" do
|
96
|
+
Net::SNMP::Session.open(:peername => 'localhost') do |sess|
|
97
|
+
table = sess.columns(['ifIndex', 'ifDescr', 'ifType'])
|
98
|
+
table['1']['ifIndex'].should eql(1)
|
99
|
+
table['2']['ifDescr'].should eql('gif0')
|
100
|
+
end
|
101
|
+
end
|
91
102
|
end
|
92
103
|
|
93
104
|
context "version 2" do
|
metadata
CHANGED
@@ -5,8 +5,8 @@ version: !ruby/object:Gem::Version
|
|
5
5
|
segments:
|
6
6
|
- 0
|
7
7
|
- 2
|
8
|
-
-
|
9
|
-
version: 0.2.
|
8
|
+
- 1
|
9
|
+
version: 0.2.1
|
10
10
|
platform: ruby
|
11
11
|
authors:
|
12
12
|
- Ron McClain
|
@@ -14,7 +14,7 @@ autorequire:
|
|
14
14
|
bindir: bin
|
15
15
|
cert_chain: []
|
16
16
|
|
17
|
-
date: 2011-
|
17
|
+
date: 2011-05-01 00:00:00 -05:00
|
18
18
|
default_executable:
|
19
19
|
dependencies:
|
20
20
|
- !ruby/object:Gem::Dependency
|