Class: Iqeo::Hostspec::Hostspec

Inherits:
Object
  • Object
show all
Includes:
Enumerable
Defined in:
lib/iqeo/hostspec/hostspec.rb

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(spec_str) ⇒ Hostspec

Returns a new instance of Hostspec.

Raises:



14
15
16
17
18
19
20
21
22
23
24
25
26
27
# File 'lib/iqeo/hostspec/hostspec.rb', line 14

def initialize spec_str
  @string = spec_str
  raise HostspecException, 'spec cannot be empty' if spec_str.empty?
  host_str, mask_str = split_on_slash spec_str
  raise HostspecException, 'host cannot be empty' if host_str.empty?
  parse_mask mask_str
  begin
    parse_address_spec host_str
  rescue HostspecException
    parse_hostname host_str
  end
  raise HostspecException, 'complex spec cannot have mask length' if @mask_specified && @address_spec.any? { |octet| octet.size > 1 }
  mask_address_spec
end

Instance Attribute Details

#address_specObject (readonly)

Returns the value of attribute address_spec.



12
13
14
# File 'lib/iqeo/hostspec/hostspec.rb', line 12

def address_spec
  @address_spec
end

#hostnameObject (readonly)

Returns the value of attribute hostname.



12
13
14
# File 'lib/iqeo/hostspec/hostspec.rb', line 12

def hostname
  @hostname
end

#maskObject (readonly)

Returns the value of attribute mask.



12
13
14
# File 'lib/iqeo/hostspec/hostspec.rb', line 12

def mask
  @mask
end

#mask_lengthObject (readonly)

Returns the value of attribute mask_length.



12
13
14
# File 'lib/iqeo/hostspec/hostspec.rb', line 12

def mask_length
  @mask_length
end

#stringObject (readonly)

Returns the value of attribute string.



12
13
14
# File 'lib/iqeo/hostspec/hostspec.rb', line 12

def string
  @string
end

Instance Method Details

#check_octet_value(str) ⇒ Object

Raises:



111
112
113
114
# File 'lib/iqeo/hostspec/hostspec.rb', line 111

def check_octet_value str
  match = str.match /^(25[0-5]|2[0-4]\d|[0-1]\d\d|\d\d|\d)$/
  raise HostspecException, "bad ip, octet value is not a number in 0-255: #{str}" unless match
end

#each_addressObject Also known as: each



137
138
139
140
141
142
143
144
145
# File 'lib/iqeo/hostspec/hostspec.rb', line 137

def each_address 
  if block_given?
    recursively_iterate_octets do |address_str|
      yield address_str
    end
  else
    return to_enum( :each_address ) { size }
  end
end

#lastObject



161
162
163
164
165
# File 'lib/iqeo/hostspec/hostspec.rb', line 161

def last
  address = nil
  each { |addr| address = addr }
  address
end

#mask_address_specObject



55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
# File 'lib/iqeo/hostspec/hostspec.rb', line 55

def mask_address_spec
  @address_spec.each_with_index do |octet,index|
    high_bit_position = ( index * 8 ) + 1 
    low_bit_position = ( index + 1 ) * 8
    @address_spec[index] = case
                           when @mask_length >= low_bit_position then octet
                           when @mask_length < high_bit_position then [0..255]
                           else
                             octet_mask_length = @mask_length % 8
                             octet_mask = ( ( 2 ** octet_mask_length ) - 1 ) << ( 8 - octet_mask_length )
                             octet_mask_inverted = octet_mask ^ 255
                             octet_min = octet_mask & octet[0]
                             octet_max = octet_min | octet_mask_inverted
                             [octet_min..octet_max]
                           end
  end
end

#maxObject



167
168
169
# File 'lib/iqeo/hostspec/hostspec.rb', line 167

def max
  last
end

#minObject



157
158
159
# File 'lib/iqeo/hostspec/hostspec.rb', line 157

def min
  first
end

#minmaxObject



171
172
173
# File 'lib/iqeo/hostspec/hostspec.rb', line 171

def minmax
  [first,last]
end

#parse_address_spec(str) ⇒ Object

Raises:



73
74
75
76
77
78
# File 'lib/iqeo/hostspec/hostspec.rb', line 73

def parse_address_spec str
  octet_strs = str.split '.'
  raise HostspecException, 'bad ip, expected 4 octets' unless octet_strs.size == 4    
  octets = octet_strs.collect { |octet_str| parse_octet octet_str }
  @address_spec = octets
end

#parse_hostname(str) ⇒ Object



116
117
118
119
# File 'lib/iqeo/hostspec/hostspec.rb', line 116

def parse_hostname str
  @hostname = str
  parse_address_spec Resolv.getaddress(str)
end

#parse_mask(str) ⇒ Object



37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
# File 'lib/iqeo/hostspec/hostspec.rb', line 37

def parse_mask str
  if str.empty?
    @mask = '255.255.255.255'
    @mask_length = 32
    @mask_specified = false
    return
  end
  if match = str.match( /^\d+$/ )
    @mask_length = match[0].to_i
    raise "bad mask length (#{@mask_length}), expected between 0 ad 32" unless @mask_length.between? 0,32
    mask_int = ((2**@mask_length)-1) << (32-@mask_length)
    @mask = [24,16,8,0].collect { |n| ( mask_int & ( 255 << n ) ) >> n }.join '.'
    @mask_specified = true
  else
    raise "bad format, expected mask length after '/'"
  end
end

#parse_octet(str) ⇒ Object



80
81
82
83
# File 'lib/iqeo/hostspec/hostspec.rb', line 80

def parse_octet str
  values = str.split ','
  values.collect { |value_str| parse_octet_value value_str }
end

#parse_octet_value(str) ⇒ Object



85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
# File 'lib/iqeo/hostspec/hostspec.rb', line 85

def parse_octet_value str
  # values may be dash denoted ranges, possibilities...
  #   n   : just a number         :   'n'.split '-' == ['n']       <= same = problem!    'n'.split '-', -1 == [ "n"       ] 
  #   n-m : range from n to m     : 'n-m'.split '-' == ['n','m']                       'n-m'.split '-', -1 == [ "n" , "m" ]
  #   n-  : range from n to 255   :  'n-'.split '-' == ['n']       <= same = problem!   'n-'.split '-', -1 == [ "n" , ""  ]
  #   -m  : range from 0 to m     :  '-m'.split '-' == ['','m']                         '-m'.split '-', -1 == [ ""  , "m" ]
  #   -   : range from 0 to 255   :   '-'.split '-' == []                                '-'.split '-', -1 == [ ""  , ""  ]
  numbers = str.split '-', -1 # maximize return fields to distinguish 'n' from '-m'
  case numbers.size
  when 1 then
    check_octet_value numbers[0]
    numbers[0].to_i
  when 2 then
    numbers[0] =   '0' if numbers[0].empty?
    numbers[1] = '255' if numbers[1].empty?
    check_octet_value numbers[0]
    check_octet_value numbers[1]
    range_start = numbers[0].to_i
    range_finish = numbers[1].to_i
    raise HostspecException, "bad ip, reversed range in octet value: #{str}" if range_start > range_finish
    range_start..range_finish
  else
    raise HostspecException, "bad ip, invalid octet value: #{str}"
  end
end

#recursively_iterate_octets(octet_index = 0, address = [], &block) ⇒ Object



121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
# File 'lib/iqeo/hostspec/hostspec.rb', line 121

def recursively_iterate_octets octet_index = 0, address = [], &block
  @address_spec[octet_index].each do |item|
    if item.respond_to? :each
      item.each do |value|
        address.push value
        octet_index == 3 ? yield( address.join '.' ) : recursively_iterate_octets( octet_index + 1, address, &block )
        address.pop
      end
    else
      address.push item
      octet_index == 3 ? yield( address.join '.' ) : recursively_iterate_octets( octet_index + 1, address, &block )
      address.pop
    end
  end
end

#sizeObject



149
150
151
152
153
154
155
# File 'lib/iqeo/hostspec/hostspec.rb', line 149

def size
  if @mask_length == 32
    @address_spec.inject(1) { |oc,o| oc * o.inject(0) { |vc,v| vc + ( v.respond_to?(:each) ? v.size : 1 ) } }
  else
    2**(32-@mask_length)
  end
end

#split_on_slash(str) ⇒ Object



29
30
31
32
33
34
35
# File 'lib/iqeo/hostspec/hostspec.rb', line 29

def split_on_slash str
  case str.count '/'
  when 0 then [ str.strip, '' ]
  when 1 then str.strip.split '/'
  else raise 'bad format, expected 0 or 1 "/"'
  end
end