resolv-srv 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: b52d06ac3497bab2fa8922e14a2c2bcb1d9fb639
4
+ data.tar.gz: b3af0aaa18a42710a43312089286807e1b75fe0d
5
+ SHA512:
6
+ metadata.gz: 039252fd5c46c66b71ca38b444c364ca93294b00e151f1ced4b99a66ae73b3e8652c6e3234570266ef1ec00e915e3a84c4a33fd20dddd77e3e54505745bf1018
7
+ data.tar.gz: 86e6293c859759d2c3b43a2db1e1428d002a0f6e1d932242e102daa563b6c9c6c4c473c4c05e79c8e2f672adb4dadb6e69ea7340d18f4c054921696ce6fbd5fe
@@ -0,0 +1 @@
1
+ --protected --private --main README.md lib/**/*.rb - NEWS.md LICENSE
data/LICENSE ADDED
@@ -0,0 +1,22 @@
1
+ (The MIT License)
2
+
3
+ Copyright (c) 2015 Jeremy Bopp
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ 'Software'), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
19
+ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
20
+ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
21
+ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
22
+ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/NEWS.md ADDED
@@ -0,0 +1,11 @@
1
+ # News and Notifications by Version
2
+
3
+ This file lists noteworthy changes which may affect users of this project. More
4
+ detailed information is available in the rest of the documentation.
5
+
6
+ **NOTE:** Date stamps in the following entries are in YYYY/MM/DD format.
7
+
8
+
9
+ ## v0.0.1 (2015/08/03)
10
+
11
+ * Birthday
@@ -0,0 +1,135 @@
1
+ # Resolv SRV
2
+
3
+ Resolve and iterate over SRV DNS records correctly.
4
+
5
+ ## Links
6
+
7
+ * Homepage :: https://github.com/javanthropus/resolv-srv
8
+ * Source :: https://github.com/javanthropus/resolv-srv.git
9
+
10
+ ## Description
11
+
12
+ This gem patches the Resolv::DNS class in stdlib to include a method to resolve
13
+ and iterate over SRV records according to their relative priorities and weights.
14
+
15
+ ## Features
16
+
17
+ * Iterate over SRV resources in order by priority and randomly in proportion to
18
+ weight.
19
+
20
+ ## Known Bugs/Limitations
21
+
22
+ * None so far...
23
+
24
+ ## Synopsis
25
+
26
+ Look up your user information in Active Directory (assumes `/etc/ssl/certs`
27
+ contains the internal CA certificate for the domain):
28
+
29
+ ```ruby
30
+ #!/usr/bin/env ruby
31
+
32
+ require 'net/ldap'
33
+ require 'pp'
34
+ require 'resolv-srv'
35
+
36
+ def search_ldap(domain, username, password, search_args = {})
37
+ base = domain.split('.').map { |n| "dc=#{n}" }.join(',')
38
+ Resolv::DNS.open do |dns|
39
+ dns.each_srv_resource('ldap', 'tcp', domain) do |srv|
40
+ begin
41
+ Net::LDAP.open(
42
+ host: srv.target.to_s,
43
+ port: srv.port,
44
+ base: base,
45
+ auth: {
46
+ method: :simple,
47
+ username: username,
48
+ password: password,
49
+ },
50
+ encryption: {
51
+ method: :start_tls,
52
+ tls_options: { ca_path: '/etc/ssl/certs' }
53
+ },
54
+ ) do |ldap|
55
+ return ldap.search(search_args)
56
+ end
57
+ rescue Net::LDAP::Error, OpenSSL::SSL::SSLError
58
+ puts "Failed with host #{srv.target} on port #{srv.port}: #{$!}"
59
+ end
60
+ end
61
+ end
62
+ end
63
+
64
+ print 'AD Domain: '
65
+ domain = gets.chomp
66
+ print 'AD Username: '
67
+ username = gets.chomp
68
+ print "AD Password (#{username}): "
69
+ password = ($stdin.tty? ? $stdin.noecho(&:gets) : $stdin.gets).chomp
70
+ puts
71
+
72
+ pp search_ldap(
73
+ domain,
74
+ "#{username}@#{domain}",
75
+ password,
76
+ filter: "sAMAccountName=#{username}"
77
+ )
78
+ ```
79
+
80
+ ## Requirements
81
+
82
+ None
83
+
84
+ ## Contributing
85
+
86
+ Contributions for bug fixes, documentation, extensions, tests, etc. are
87
+ encouraged.
88
+
89
+ 1. Clone the repository.
90
+ 2. Fix a bug or add a feature.
91
+ 3. Add tests for the fix or feature.
92
+ 4. Make a pull request.
93
+
94
+ ## Development
95
+
96
+ After checking out the source, run:
97
+
98
+ $ bundle install
99
+ $ bundle exec rake test yard
100
+
101
+ This will install all dependencies, run the tests/specs, and generate the
102
+ documentation.
103
+
104
+ ## Authors
105
+
106
+ Thanks to all contributors. Without your help this project would not exist.
107
+
108
+ * Jeremy Bopp :: jeremy@bopp.net
109
+
110
+ ## License
111
+
112
+ ```
113
+ (The MIT License)
114
+
115
+ Copyright (c) 2015 Jeremy Bopp
116
+
117
+ Permission is hereby granted, free of charge, to any person obtaining
118
+ a copy of this software and associated documentation files (the
119
+ 'Software'), to deal in the Software without restriction, including
120
+ without limitation the rights to use, copy, modify, merge, publish,
121
+ distribute, sublicense, and/or sell copies of the Software, and to
122
+ permit persons to whom the Software is furnished to do so, subject to
123
+ the following conditions:
124
+
125
+ The above copyright notice and this permission notice shall be
126
+ included in all copies or substantial portions of the Software.
127
+
128
+ THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
129
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
130
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
131
+ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
132
+ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
133
+ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
134
+ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
135
+ ```
@@ -0,0 +1,220 @@
1
+ # encoding: UTF-8
2
+ # -*- ruby -*-
3
+
4
+ require 'erb'
5
+ require 'rake/testtask'
6
+ require 'rubygems/package_task'
7
+ require 'rake/clean'
8
+ require 'yard'
9
+
10
+ # Load the gemspec file for this project.
11
+ GEMSPEC = Dir['*.gemspec'].first
12
+ SPEC = eval(File.read(GEMSPEC), nil, GEMSPEC)
13
+
14
+ # A dynamically generated list of files that should match the manifest (the
15
+ # combined contents of SPEC.files and SPEC.test_files). The idea is for this
16
+ # list to contain all project files except for those that have been explicitly
17
+ # excluded. This list will be compared with the manifest from the SPEC in order
18
+ # to help catch the addition or removal of files to or from the project that
19
+ # have not been accounted for either by an exclusion here or an inclusion in the
20
+ # SPEC manifest.
21
+ #
22
+ # NOTE:
23
+ # It is critical that the manifest is *not* automatically generated via globbing
24
+ # and the like; otherwise, this will yield a simple comparison between
25
+ # redundantly generated lists of files that probably will not protect the
26
+ # project from the unintentional inclusion or exclusion of files in the
27
+ # distribution.
28
+ PKG_FILES = FileList.new(Dir.glob('**/*', File::FNM_DOTMATCH)) do |files|
29
+ # Exclude anything that doesn't exist as well as directories.
30
+ files.exclude {|file| ! File.exist?(file) || File.directory?(file)}
31
+ # Exclude Git administrative files.
32
+ files.exclude(%r{(^|[/\\])\.git(ignore|modules|keep)?([/\\]|$)})
33
+ # Exclude editor swap/temporary files.
34
+ files.exclude('**/.*.sw?')
35
+ # Exclude the gemspec file.
36
+ files.exclude(GEMSPEC)
37
+ # Exclude the README template file.
38
+ files.exclude('README.md.erb')
39
+ # Exclude resources for bundler.
40
+ files.exclude('Gemfile', 'Gemfile.lock')
41
+ files.exclude(%r{^.bundle([/\\]|$)})
42
+ files.exclude(%r{^vendor/bundle([/\\]|$)})
43
+ # Exclude generated content, except for the README file.
44
+ files.exclude(%r{^(pkg|doc|.yardoc)([/\\]|$)})
45
+ # Exclude Rubinius compiled Ruby files.
46
+ files.exclude('**/*.rbc')
47
+ end
48
+
49
+ # Make sure that :clean and :clobber will not whack the repository files.
50
+ CLEAN.exclude('.git/**')
51
+ # Vim swap files are fair game for clean up.
52
+ CLEAN.include('**/.*.sw?')
53
+
54
+ # Returns the value of the VERSION environment variable as a Gem::Version object
55
+ # assuming it is set and a valid Gem version string. Otherwise, raises an
56
+ # exception.
57
+ def get_version_argument
58
+ version = ENV['VERSION']
59
+ if version.to_s.empty?
60
+ raise "No version specified: Add VERSION=X.Y.Z to the command line"
61
+ end
62
+ begin
63
+ Gem::Version.create(version.dup)
64
+ rescue ArgumentError
65
+ raise "Invalid version specified in `VERSION=#{version}'"
66
+ end
67
+ end
68
+
69
+ # Performs an in place, per line edit of the file indicated by _path_ by calling
70
+ # the sub method on each line and passing _pattern_, _replacement_, and _b_ as
71
+ # arguments.
72
+ def file_sub(path, pattern, replacement = nil, &b)
73
+ tmp_path = "#{path}.tmp"
74
+ File.open(path) do |infile|
75
+ File.open(tmp_path, 'w') do |outfile|
76
+ infile.each do |line|
77
+ outfile.write(line.sub(pattern, replacement, &b))
78
+ end
79
+ end
80
+ end
81
+ File.rename(tmp_path, path)
82
+ end
83
+
84
+ # Updates the version string in the gemspec file to the string in _version_.
85
+ def set_version(version)
86
+ file_sub(GEMSPEC, /(\.version\s*=\s*).*/, "\\1'#{version}'")
87
+ end
88
+
89
+ # Returns a string that is line wrapped at word boundaries, where each line is
90
+ # no longer than _line_width_ characters.
91
+ #
92
+ # This is mostly lifted directly from ActionView::Helpers::TextHelper.
93
+ def word_wrap(text, line_width = 80)
94
+ text.split("\n").collect do |line|
95
+ line.length > line_width ?
96
+ line.gsub(/(.{1,#{line_width}})(\s+|$)/, "\\1\n").strip :
97
+ line
98
+ end * "\n"
99
+ end
100
+
101
+ desc 'Alias for build:gem'
102
+ task :build => 'build:gem'
103
+
104
+ # Build related tasks.
105
+ namespace :build do
106
+ # Create the gem and package tasks.
107
+ Gem::PackageTask.new(SPEC).define
108
+
109
+ # Ensure that the manifest is consulted when building the gem. Any
110
+ # generated/compiled files should be available at that time.
111
+ task :gem => :check_manifest
112
+
113
+ desc 'Verify the manifest'
114
+ task :check_manifest do
115
+ manifest_files = (SPEC.files + SPEC.test_files).sort.uniq
116
+ pkg_files = PKG_FILES.sort.uniq
117
+ if manifest_files != pkg_files then
118
+ common_files = manifest_files & pkg_files
119
+ manifest_files -= common_files
120
+ pkg_files -= common_files
121
+ message = ["The manifest does not match the automatic file list."]
122
+ unless manifest_files.empty? then
123
+ message << " Extraneous files:\n " + manifest_files.join("\n ")
124
+ end
125
+ unless pkg_files.empty?
126
+ message << " Missing files:\n " + pkg_files.join("\n ")
127
+ end
128
+ raise message.join("\n")
129
+ end
130
+ end
131
+
132
+ # Creates the README.md file from its template and other sources.
133
+ file 'README.md' => ['README.md.erb', 'LICENSE', GEMSPEC] do
134
+ spec = SPEC
135
+ File.open('README.md', 'w') do |readme|
136
+ readme.write(
137
+ ERB.new(File.read('README.md.erb'), nil, '-').result(binding)
138
+ )
139
+ end
140
+ end
141
+ end
142
+
143
+ # Ensure that the clobber task also clobbers package files.
144
+ task :clobber => 'build:clobber_package'
145
+
146
+ # Create the documentation task.
147
+ YARD::Rake::YardocTask.new
148
+ # Ensure that the README file is (re)generated first.
149
+ task :yard => 'README.md'
150
+
151
+ # Gem related tasks.
152
+ namespace :gem do
153
+ desc 'Alias for build:gem'
154
+ task :build => 'build:gem'
155
+
156
+ desc 'Publish the gemfile'
157
+ task :publish => ['version:check', :test, 'repo:tag', :build] do
158
+ sh "gem push pkg/#{SPEC.name}-#{SPEC.version}*.gem"
159
+ end
160
+ end
161
+
162
+ Rake::TestTask.new do |t|
163
+ t.pattern = 'spec/**/*_spec.rb'
164
+ end
165
+
166
+ # Version string management tasks.
167
+ namespace :version do
168
+ desc 'Set the version for the project to a specified version'
169
+ task :set do
170
+ set_version(get_version_argument)
171
+ end
172
+
173
+ desc 'Set the version for the project back to 0.0.0'
174
+ task :reset do
175
+ set_version('0.0.0')
176
+ end
177
+
178
+ desc 'Check that all version strings are correctly set'
179
+ task :check => ['version:check:spec', 'version:check:news']
180
+
181
+ namespace :check do
182
+ desc 'Check that the version in the gemspec is correctly set'
183
+ task :spec do
184
+ version = get_version_argument
185
+ if version != SPEC.version
186
+ raise "The given version `#{version}' does not match the gemspec version `#{SPEC.version}'"
187
+ end
188
+ end
189
+
190
+ desc 'Check that the NEWS.md file mentions the version'
191
+ task :news do
192
+ version = get_version_argument
193
+ begin
194
+ File.open('NEWS.md') do |news|
195
+ unless news.each_line.any? {|l| l =~ /^## v#{Regexp.escape(version.to_s)} /}
196
+ raise "The NEWS.md file does not mention version `#{version}'"
197
+ end
198
+ end
199
+ rescue Errno::ENOENT
200
+ raise 'No NEWS.md file found'
201
+ end
202
+ end
203
+ end
204
+ end
205
+
206
+ # Repository and workspace management tasks.
207
+ namespace :repo do
208
+ desc 'Tag the current HEAD with the version string'
209
+ task :tag => :check_workspace do
210
+ version = get_version_argument
211
+ sh "git tag -s -m 'Release v#{version}' v#{version}"
212
+ end
213
+
214
+ desc 'Ensure the workspace is fully committed and clean'
215
+ task :check_workspace => ['README.md'] do
216
+ unless `git status --untracked-files=all --porcelain`.empty?
217
+ raise 'Workspace has been modified. Commit pending changes and try again.'
218
+ end
219
+ end
220
+ end
@@ -0,0 +1,67 @@
1
+ require 'resolv'
2
+
3
+ ##
4
+ # A monkey patch for Resolv::DNS that provides a mostly RFC-compliant method for
5
+ # resolving SRV records.
6
+ class Resolv::DNS
7
+ ##
8
+ # Iterates over SRV resources for _service_ operating over _protocol_ within
9
+ # _domain_, first in order of priority and then randomly within a priority in
10
+ # proportion to weight.
11
+ #
12
+ # *NOTE:* The algorithm used causes resources with weight 0 to be selected
13
+ # before resources with higher weights slightly more often than they would be
14
+ # if strict RFC compliance were enforced.
15
+ #
16
+ # @param service [String] The service type, such as +ldap+ or +http+.
17
+ # @param protocol [String] The protocol for connections, such as +tcp+ or
18
+ # +udp+.
19
+ # @param domain [String] The DNS domain in which to search for records.
20
+ #
21
+ # @yield Resolv::DNS::Resource::IN::SRV
22
+ def each_srv_resource(service, protocol, domain)
23
+ if service.nil? || service.empty? || service.index('.')
24
+ raise ArgumentError, "Invalid service name: #{service.inspect}"
25
+ end
26
+ if protocol.nil? || protocol.empty? || protocol.index('.')
27
+ raise ArgumentError, "Invalid protocol name: #{protocol.inspect}"
28
+ end
29
+
30
+ name = "_#{service}._#{protocol}.#{domain}"
31
+
32
+ # Fetch the resources.
33
+ getresources(name, Resolv::DNS::Resource::IN::SRV).
34
+ # Group and sort them by priority.
35
+ sort_by!(&:priority).chunk(&:priority).sort.
36
+ # Iterate over the lists of resources at each priority level.
37
+ each do |priority, available|
38
+ # NOTE:
39
+ # All weight processing is shifted to be 1-based rather than 0-based.
40
+ # Because of the way selection is handled, this avoids needing to shuffle
41
+ # or sort the array elements by weight while ensuring that resources with
42
+ # weight 0 avoid ALWAYS being selected last. The trade-off is that
43
+ # resources with weight 0 may be selected before other resources slightly
44
+ # more often than otherwise.
45
+
46
+ # Tracks the total weight of all resources remaining in the available
47
+ # list.
48
+ total_weight = available.inject(0) { |sum, e| sum + e.weight + 1 }
49
+
50
+ until available.empty?
51
+ # Randomly select from the available list such that the probability of
52
+ # selecting a resource is proportional to the resource's weight.
53
+ selector = Integer(rand * total_weight) + 1
54
+ selected_idx = available.find_index do |e|
55
+ selector -= e.weight + 1
56
+ selector <= 0
57
+ end
58
+ selected = available.delete_at(selected_idx)
59
+
60
+ # Account for the removal of a resource from the available list.
61
+ total_weight -= selected.weight + 1
62
+
63
+ yield(selected)
64
+ end
65
+ end
66
+ end
67
+ end
@@ -0,0 +1,146 @@
1
+ require 'minitest/autorun'
2
+ require 'minitest/mock'
3
+ require 'minitest/spec'
4
+
5
+ require 'resolv-srv'
6
+
7
+ describe "each_srv_resource" do
8
+ before do
9
+ @dns = Resolv::DNS.new
10
+ domain = 'example.com'
11
+ hostname_template = "foo%i-%i-%i.#{domain}"
12
+ @prioritized_weights = [
13
+ [0, 0, 100, 400, 400],
14
+ [100],
15
+ [400, 400],
16
+ [1, 2, 3, 4, 5],
17
+ ]
18
+ @srv_resources =
19
+ @prioritized_weights.
20
+ to_enum(:each_with_index).
21
+ flat_map do |weights, priority|
22
+ weights.each_with_index.map do |weight, n|
23
+ Resolv::DNS::Resource::IN::SRV.new(
24
+ priority, weight, 12345, hostname_template % [n, priority, weight]
25
+ )
26
+ end
27
+ end.shuffle
28
+ end
29
+
30
+ after do
31
+ @dns.close
32
+ end
33
+
34
+ it 'raises an exception if the service name is invalid' do
35
+ -> {
36
+ @dns.each_srv_resource('bad.service.name', 'tcp', 'example.com') {}
37
+ }.must_raise(ArgumentError)
38
+ end
39
+
40
+ it 'raises an exception if the service name is empty' do
41
+ -> {
42
+ @dns.each_srv_resource('', 'tcp', 'example.com') {}
43
+ }.must_raise(ArgumentError)
44
+ end
45
+
46
+ it 'raises an exception if the service name is nil' do
47
+ -> {
48
+ @dns.each_srv_resource(nil, 'tcp', 'example.com') {}
49
+ }.must_raise(ArgumentError)
50
+ end
51
+
52
+ it 'raises an exception if the protocol name is invalid' do
53
+ -> {
54
+ @dns.each_srv_resource('ldap', 'bad.protocol.name', 'example.com') {}
55
+ }.must_raise(ArgumentError)
56
+ end
57
+
58
+ it 'raises an exception if the protocol name is empty' do
59
+ -> {
60
+ @dns.each_srv_resource('ldap', '', 'example.com') {}
61
+ }.must_raise(ArgumentError)
62
+ end
63
+
64
+ it 'raises an exception if the protocol name is nil' do
65
+ -> {
66
+ @dns.each_srv_resource('ldap', nil, 'example.com') {}
67
+ }.must_raise(ArgumentError)
68
+ end
69
+
70
+ it 'orders by priority' do
71
+ @dns.stub(:getresources, @srv_resources) do
72
+ @dns.to_enum(:each_srv_resource, 'ldap', 'tcp', 'example.com').
73
+ map do |srv|
74
+ srv.priority
75
+ end.
76
+ must_equal(
77
+ @prioritized_weights.
78
+ to_enum(:each_with_index).
79
+ flat_map do |weights, priority|
80
+ [priority] * weights.size
81
+ end
82
+ )
83
+ end
84
+ end
85
+
86
+ it 'orders randomly in proportion to weight' do
87
+ results = Hash.new do |h, priority|
88
+ h[priority] = Hash.new do |h2, srv|
89
+ h2[srv] = Array.new(@prioritized_weights[priority].size, 0)
90
+ end
91
+ end
92
+
93
+ rounds = 100_000
94
+ @dns.stub(:getresources, @srv_resources) do
95
+ rounds.times do
96
+ selection = -1
97
+ old_priority = 0
98
+ @dns.each_srv_resource('ldap', 'tcp', 'example.com') do |srv|
99
+ if srv.priority != old_priority
100
+ old_priority = srv.priority
101
+ selection = 0
102
+ else
103
+ selection += 1
104
+ end
105
+
106
+ results[srv.priority][srv][selection] += 1
107
+ end
108
+ end
109
+ end
110
+
111
+ results.each do |priority, srv_selections|
112
+ srv_selections.each do |srv, selections|
113
+ selections.each_with_index do |hits, position|
114
+ expected = expected_probability(
115
+ position, srv.weight, @prioritized_weights[priority]
116
+ )
117
+ actual = Float(hits) / rounds
118
+ actual.must_be_close_to(expected, 0.02)
119
+ end
120
+ end
121
+ end
122
+ end
123
+
124
+ def expected_probability(position, selected_weight, weights)
125
+ return first_probability(selected_weight, weights) if position == 0
126
+
127
+ simple_remove(weights, selected_weight).inject(0) do |sum, w|
128
+ sum +
129
+ first_probability(w, weights) *
130
+ expected_probability(
131
+ position - 1, selected_weight, simple_remove(weights, w)
132
+ )
133
+ end
134
+ end
135
+
136
+ def first_probability(selected_weight, weights)
137
+ total_weight = weights.inject(0) { |sum, weight| sum + weight + 1 }
138
+ Float(selected_weight + 1) / total_weight
139
+ end
140
+
141
+ def simple_remove(array, element)
142
+ array = array.dup
143
+ array.delete_at(array.find_index(element))
144
+ array
145
+ end
146
+ end
metadata ADDED
@@ -0,0 +1,168 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: resolv-srv
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Jeremy Bopp
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2015-08-03 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: rake
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '10.1'
20
+ - - ">"
21
+ - !ruby/object:Gem::Version
22
+ version: 10.1.1
23
+ type: :development
24
+ prerelease: false
25
+ version_requirements: !ruby/object:Gem::Requirement
26
+ requirements:
27
+ - - "~>"
28
+ - !ruby/object:Gem::Version
29
+ version: '10.1'
30
+ - - ">"
31
+ - !ruby/object:Gem::Version
32
+ version: 10.1.1
33
+ - !ruby/object:Gem::Dependency
34
+ name: minitest
35
+ requirement: !ruby/object:Gem::Requirement
36
+ requirements:
37
+ - - "~>"
38
+ - !ruby/object:Gem::Version
39
+ version: '5.3'
40
+ - - ">"
41
+ - !ruby/object:Gem::Version
42
+ version: 5.3.1
43
+ type: :development
44
+ prerelease: false
45
+ version_requirements: !ruby/object:Gem::Requirement
46
+ requirements:
47
+ - - "~>"
48
+ - !ruby/object:Gem::Version
49
+ version: '5.3'
50
+ - - ">"
51
+ - !ruby/object:Gem::Version
52
+ version: 5.3.1
53
+ - !ruby/object:Gem::Dependency
54
+ name: yard
55
+ requirement: !ruby/object:Gem::Requirement
56
+ requirements:
57
+ - - "~>"
58
+ - !ruby/object:Gem::Version
59
+ version: 0.8.7
60
+ - - ">"
61
+ - !ruby/object:Gem::Version
62
+ version: 0.8.7.3
63
+ type: :development
64
+ prerelease: false
65
+ version_requirements: !ruby/object:Gem::Requirement
66
+ requirements:
67
+ - - "~>"
68
+ - !ruby/object:Gem::Version
69
+ version: 0.8.7
70
+ - - ">"
71
+ - !ruby/object:Gem::Version
72
+ version: 0.8.7.3
73
+ - !ruby/object:Gem::Dependency
74
+ name: redcarpet
75
+ requirement: !ruby/object:Gem::Requirement
76
+ requirements:
77
+ - - "~>"
78
+ - !ruby/object:Gem::Version
79
+ version: '3.1'
80
+ - - ">"
81
+ - !ruby/object:Gem::Version
82
+ version: 3.1.0
83
+ type: :development
84
+ prerelease: false
85
+ version_requirements: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - "~>"
88
+ - !ruby/object:Gem::Version
89
+ version: '3.1'
90
+ - - ">"
91
+ - !ruby/object:Gem::Version
92
+ version: 3.1.0
93
+ - !ruby/object:Gem::Dependency
94
+ name: github-markup
95
+ requirement: !ruby/object:Gem::Requirement
96
+ requirements:
97
+ - - "~>"
98
+ - !ruby/object:Gem::Version
99
+ version: '1.0'
100
+ - - ">"
101
+ - !ruby/object:Gem::Version
102
+ version: 1.0.2
103
+ type: :development
104
+ prerelease: false
105
+ version_requirements: !ruby/object:Gem::Requirement
106
+ requirements:
107
+ - - "~>"
108
+ - !ruby/object:Gem::Version
109
+ version: '1.0'
110
+ - - ">"
111
+ - !ruby/object:Gem::Version
112
+ version: 1.0.2
113
+ - !ruby/object:Gem::Dependency
114
+ name: pry
115
+ requirement: !ruby/object:Gem::Requirement
116
+ requirements:
117
+ - - "~>"
118
+ - !ruby/object:Gem::Version
119
+ version: '0'
120
+ type: :development
121
+ prerelease: false
122
+ version_requirements: !ruby/object:Gem::Requirement
123
+ requirements:
124
+ - - "~>"
125
+ - !ruby/object:Gem::Version
126
+ version: '0'
127
+ description: |
128
+ This gem patches the Resolv::DNS class in stdlib to include a method to resolve
129
+ and iterate over SRV records according to their relative priorities and weights.
130
+ email:
131
+ - jeremy@bopp.net
132
+ executables: []
133
+ extensions: []
134
+ extra_rdoc_files: []
135
+ files:
136
+ - ".yardopts"
137
+ - LICENSE
138
+ - NEWS.md
139
+ - README.md
140
+ - Rakefile
141
+ - lib/resolv-srv.rb
142
+ - spec/each_srv_resource_spec.rb
143
+ homepage: https://github.com/javanthropus/resolv-srv
144
+ licenses:
145
+ - MIT
146
+ metadata: {}
147
+ post_install_message:
148
+ rdoc_options: []
149
+ require_paths:
150
+ - lib
151
+ required_ruby_version: !ruby/object:Gem::Requirement
152
+ requirements:
153
+ - - ">="
154
+ - !ruby/object:Gem::Version
155
+ version: '0'
156
+ required_rubygems_version: !ruby/object:Gem::Requirement
157
+ requirements:
158
+ - - ">="
159
+ - !ruby/object:Gem::Version
160
+ version: '0'
161
+ requirements: []
162
+ rubyforge_project:
163
+ rubygems_version: 2.4.6
164
+ signing_key:
165
+ specification_version: 4
166
+ summary: Resolve and iterate over SRV DNS records correctly.
167
+ test_files:
168
+ - spec/each_srv_resource_spec.rb