dns_guru 0.1

Sign up to get free protection for your applications and to get access to all the features.
data/README ADDED
File without changes
data/Rakefile ADDED
@@ -0,0 +1,43 @@
1
+ require 'rubygems'
2
+ require 'rake'
3
+ require 'rake/testtask'
4
+ require 'rake/gempackagetask'
5
+
6
+ task :default => [:test]
7
+
8
+ desc 'Tests'
9
+ Rake::TestTask.new(:test) do |t|
10
+ t.libs << "test"
11
+ t.test_files = Dir.glob("test/**/test_*.rb")
12
+ t.verbose = true
13
+ end
14
+
15
+ PKG_FILES = FileList[
16
+ '[a-zA-Z]*',
17
+ 'generators/**/*',
18
+ 'lib/**/*',
19
+ 'rails/**/*',
20
+ 'tasks/**/*',
21
+ 'test/**/*'
22
+ ]
23
+
24
+ spec = Gem::Specification.new do |s|
25
+ s.name = "dns_guru"
26
+ s.version = "0.1"
27
+ s.author = "Dns Guru"
28
+ s.email = "ken.miller@gmail.com"
29
+ s.homepage = "http://github.com/kemiller/dns_guru"
30
+ s.platform = Gem::Platform::RUBY
31
+ s.summary = "Parse hostnames into useful information with a routes-like syntax"
32
+ s.files = PKG_FILES.to_a
33
+ s.require_path = "lib"
34
+ s.has_rdoc = false
35
+ s.extra_rdoc_files = ["README"]
36
+ end
37
+
38
+ desc 'Turn this plugin into a gem.'
39
+ Rake::GemPackageTask.new(spec) do |pkg|
40
+ pkg.gem_spec = spec
41
+ end
42
+
43
+
data/init.rb ADDED
@@ -0,0 +1,27 @@
1
+
2
+ $: << File.join(File.dirname(__FILE__), "lib")
3
+ require 'dns_guru'
4
+ require 'rack'
5
+ require 'action_controller/test_process'
6
+
7
+ config_file = File.join(File.dirname(__FILE__), "../../../config/hosts.rb")
8
+ DnsGuru.init(config_file)
9
+
10
+ class Rack::Request
11
+ include DnsGuru::RequestMixin
12
+ end
13
+
14
+ class ActionController::Request
15
+ include DnsGuru::RequestMixin
16
+ end
17
+
18
+ class ActionController::TestRequest
19
+ include DnsGuru::RequestMixin
20
+ end
21
+
22
+ class ActionController::Base
23
+ include DnsGuru::ControllerMixin
24
+
25
+ helper_method :host_name
26
+ helper_method :host_name_params
27
+ end
@@ -0,0 +1,15 @@
1
+
2
+ module DnsGuru
3
+ module ControllerMixin
4
+ def host_name(options = {})
5
+ host = request.canonical_host_name(options)
6
+ if request.port && request.port != 80
7
+ host = "#{host}:#{request.port}"
8
+ end
9
+ host
10
+ end
11
+ def host_name_params
12
+ request.host_name_params
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,52 @@
1
+
2
+ require 'dns_guru/pattern'
3
+
4
+ module DnsGuru
5
+ class Matcher
6
+
7
+ attr_reader :patterns
8
+
9
+ def initialize(patterns = [])
10
+ @patterns = patterns
11
+ end
12
+
13
+ def match(string)
14
+ iterate(:match, string)
15
+ end
16
+
17
+ def generate(options = {})
18
+ @defaults ||= {}
19
+ iterate(:generate, @defaults.merge(options))
20
+ end
21
+
22
+ def rewrite(string, options = {})
23
+ generate(match(string).merge(options))
24
+ end
25
+
26
+ def pattern(pattern_string, params = {})
27
+ @patterns << Pattern.new(pattern_string, params)
28
+ end
29
+
30
+ def defaults(options = {})
31
+ @defaults = options
32
+ end
33
+
34
+ def current_defaults
35
+ @defaults
36
+ end
37
+
38
+ protected
39
+
40
+ def iterate(method, *args)
41
+ @patterns.each do |pat|
42
+ val = pat.send(method, *args)
43
+ if val
44
+ return val
45
+ end
46
+ end
47
+ nil
48
+ end
49
+
50
+ end
51
+
52
+ end
@@ -0,0 +1,128 @@
1
+
2
+ module DnsGuru
3
+ class Pattern
4
+
5
+ attr_reader :segments, :regexp, :params
6
+
7
+ def initialize(pattern, params={})
8
+ @params = params
9
+ parse(pattern)
10
+ end
11
+
12
+ def parse(pattern)
13
+ raw_segments = pattern.split(/(\.|-)/)
14
+
15
+ @segments = raw_segments.map do |seg|
16
+ Segment.make_segment(seg, @params)
17
+ end
18
+
19
+ @regexp = /\A#{segments.map { |s| s.substitute }.join}\Z/
20
+ end
21
+
22
+ def match(string)
23
+ md = @regexp.match(string)
24
+
25
+ unless md
26
+ return nil
27
+ end
28
+
29
+ hash = {}
30
+ md.captures.each_with_index do |m, i|
31
+ if segments[i].param
32
+ hash[segments[i].param] = m
33
+ end
34
+ end
35
+
36
+ params.merge(hash)
37
+ end
38
+
39
+ def generate(options)
40
+ options = options.dup
41
+ hostname = segments.map do |seg|
42
+ seg.generate(options)
43
+ end
44
+
45
+ if hostname.include?(nil)
46
+ return nil
47
+ end
48
+
49
+ # Whatever is left should be identical
50
+ if params == options
51
+ return hostname.join
52
+ end
53
+ end
54
+
55
+ def rewrite(domain, new_options)
56
+ options = match(domain)
57
+ if options
58
+ generate(options.merge(new_options))
59
+ end
60
+ end
61
+ end
62
+
63
+ class Segment
64
+
65
+ class << self
66
+ def inherited(klass)
67
+ types << klass
68
+ end
69
+
70
+ def types
71
+ @types ||= []
72
+ end
73
+
74
+ def make_segment(string, params = {})
75
+ klass = types.detect do |t|
76
+ t.recognize(string)
77
+ end
78
+ klass.new(string, params)
79
+ end
80
+ end
81
+
82
+ def initialize(string, params = {})
83
+ @string = string
84
+ @default = params.delete(param)
85
+ end
86
+
87
+ def param
88
+ nil
89
+ end
90
+
91
+ end
92
+
93
+ class DynamicSegment < Segment
94
+ def self.recognize(string_segment)
95
+ string_segment =~ /\A:(.*)/
96
+ end
97
+
98
+ def substitute
99
+ "([[:alnum:]_-]+)"
100
+ end
101
+
102
+ def generate(options)
103
+ unless options[param]
104
+ return @default
105
+ end
106
+ options.delete(param)
107
+ end
108
+
109
+ def param
110
+ @param ||= @string[1,1000].to_sym
111
+ end
112
+ end
113
+
114
+ class StaticSegment < Segment
115
+ def self.recognize(string_segment)
116
+ true
117
+ end
118
+
119
+ def substitute
120
+ "(#{Regexp.escape(@string)})"
121
+ end
122
+
123
+ def generate(options)
124
+ @string
125
+ end
126
+ end
127
+ end
128
+
@@ -0,0 +1,14 @@
1
+
2
+ module DnsGuru
3
+ module RequestMixin
4
+
5
+ def canonical_host_name(options = {})
6
+ DnsGuru.generate(host_name_params.merge(options))
7
+ end
8
+
9
+ def host_name_params
10
+ @host_name_params ||= DnsGuru.match(host) || DnsGuru.defaults
11
+ end
12
+
13
+ end
14
+ end
data/lib/dns_guru.rb ADDED
@@ -0,0 +1,33 @@
1
+
2
+ require 'dns_guru/matcher'
3
+ require 'dns_guru/pattern'
4
+ require 'dns_guru/request_mixin'
5
+ require 'dns_guru/controller_mixin'
6
+
7
+ module DnsGuru
8
+
9
+ def self.init(filename)
10
+ @matcher = Matcher.new([])
11
+ load filename
12
+ end
13
+
14
+ def self.read
15
+ yield(@matcher)
16
+ end
17
+
18
+ def self.match(domain)
19
+ @matcher.match(domain)
20
+ end
21
+
22
+ def self.generate(options = {})
23
+ @matcher.generate(options)
24
+ end
25
+
26
+ def self.rewrite(domain, options = {})
27
+ @matcher.rewrite(domain, options)
28
+ end
29
+
30
+ def self.defaults
31
+ @matcher.current_defaults
32
+ end
33
+ end
data/rails/init.rb ADDED
@@ -0,0 +1,27 @@
1
+
2
+ $: << File.join(File.dirname(__FILE__), "lib")
3
+ require 'dns_guru'
4
+ require 'rack'
5
+ require 'action_controller/test_process'
6
+
7
+ config_file = File.join(File.dirname(__FILE__), "../../../config/hosts.rb")
8
+ DnsGuru.init(config_file)
9
+
10
+ class Rack::Request
11
+ include DnsGuru::RequestMixin
12
+ end
13
+
14
+ class ActionController::Request
15
+ include DnsGuru::RequestMixin
16
+ end
17
+
18
+ class ActionController::TestRequest
19
+ include DnsGuru::RequestMixin
20
+ end
21
+
22
+ class ActionController::Base
23
+ include DnsGuru::ControllerMixin
24
+
25
+ helper_method :host_name
26
+ helper_method :host_name_params
27
+ end
data/test/config.rb ADDED
@@ -0,0 +1,8 @@
1
+
2
+ DnsGuru.read do |matcher|
3
+ matcher.defaults :app => 'www', :stage => 'production', :brand => 'mmp', :tld => 'com'
4
+ matcher.pattern "localhost", :app => 'www', :stage => 'development', :brand => 'mamasource', :tld => 'com'
5
+ matcher.pattern "seodev.:brand.:tld", :stage => 'qa'
6
+ matcher.pattern ":app.:brand.:tld", :stage => 'production'
7
+ matcher.pattern ":app.:stage.:brand.:tld"
8
+ end
@@ -0,0 +1,48 @@
1
+
2
+ require 'test/unit'
3
+ require 'dns_guru'
4
+
5
+ module DnsGuru
6
+ class TestControllerMixin < Test::Unit::TestCase
7
+
8
+ def setup
9
+ DnsGuru.init(File.join(File.dirname(__FILE__), "../config.rb"))
10
+ @request = MockRequest.new
11
+ @controller = MockController.new
12
+ @controller.request = @request
13
+ end
14
+
15
+ def test_host_name
16
+ @request.host = "www.production.mmp.com"
17
+ assert_equal "www.mmp.com", @controller.host_name
18
+ end
19
+
20
+ def test_host_name_with_port
21
+ @request.host = "www.production.mmp.com"
22
+ @request.port = 3000
23
+ assert_equal "www.mmp.com:3000", @controller.host_name
24
+ end
25
+
26
+ def test_host_name_params
27
+ @request.host = "www.production.mamapedia.com"
28
+ assert_equal({:app => 'www', :stage => 'production', :brand => 'mamapedia', :tld => 'com'},
29
+ @controller.host_name_params, "Wrong host name components derived from raw host name")
30
+ end
31
+
32
+ def test_host_name_params_no_host
33
+ assert_equal({:app => 'www', :stage => 'production', :brand => 'mmp', :tld => 'com'},
34
+ @controller.host_name_params, "No default values given")
35
+ end
36
+ end
37
+
38
+ class MockRequest
39
+ include RequestMixin
40
+ attr_accessor :host
41
+ attr_accessor :port
42
+ end
43
+
44
+ class MockController
45
+ include ControllerMixin
46
+ attr_accessor :request
47
+ end
48
+ end
@@ -0,0 +1,98 @@
1
+
2
+ require 'test/unit'
3
+ require 'dns_guru'
4
+
5
+ module DnsGuru
6
+ class TestMatcher < Test::Unit::TestCase
7
+
8
+ def test_truth
9
+ Matcher
10
+ end
11
+
12
+ def test_initialize
13
+ matcher = Matcher.new
14
+ assert_not_nil matcher
15
+ end
16
+
17
+ def test_match_no_hit
18
+ str = "mymatch_here"
19
+ matcher = Matcher.new([m1 = MockPattern.new, m2 = MockPattern.new])
20
+ matcher.match(str)
21
+ assert_equal str, m1.got_match, "First Pattern wasn't checked"
22
+ assert_equal str, m2.got_match, "Second Pattern wasn't checked"
23
+ end
24
+
25
+ def test_match_hit
26
+ str = "mymatch_here"
27
+ matcher = Matcher.new([m1 = MockPattern.new(true), m2 = MockPattern.new])
28
+ matcher.match(str)
29
+ assert_equal str, m1.got_match, "First Pattern wasn't checked"
30
+ assert_equal nil, m2.got_match, "Second Pattern should not have been checked"
31
+ end
32
+
33
+ def test_generate_no_hit
34
+ hash = { :str => "mygenerate_here" }
35
+ generateer = Matcher.new([m1 = MockPattern.new, m2 = MockPattern.new])
36
+ generateer.generate(hash)
37
+ assert_equal hash, m1.got_generate, "First Pattern wasn't checked"
38
+ assert_equal hash, m2.got_generate, "Second Pattern wasn't checked"
39
+ end
40
+
41
+ def test_generate_hit
42
+ hash = { :str => "mygenerate_here" }
43
+ generateer = Matcher.new([m1 = MockPattern.new(true), m2 = MockPattern.new])
44
+ generateer.generate(hash)
45
+ assert_equal hash, m1.got_generate, "First Pattern wasn't checked"
46
+ assert_equal nil, m2.got_generate, "Second Pattern should not have been checked"
47
+ end
48
+
49
+ def test_pattern
50
+ matcher = Matcher.new
51
+ matcher.pattern ":asdf.:rase", :param => 'p1'
52
+ assert_kind_of Pattern, matcher.patterns.first, "Didn't make a pattern"
53
+ end
54
+
55
+ def test_pattern_precedence
56
+ matcher = Matcher.new
57
+ matcher.pattern ":app.:brand.com", :stage => 'production'
58
+ matcher.pattern ":app.:stage.:brand.com"
59
+
60
+ assert_equal "www.mmp.com", matcher.generate(:app => 'www', :brand => 'mmp', :stage => 'production')
61
+ assert_equal "www.mmp.com", matcher.rewrite("www.production.mmp.com")
62
+ end
63
+
64
+ def test_defaults
65
+ matcher = Matcher.new
66
+ matcher.defaults :stage => 'production', :brand => 'mmp', :app => 'www'
67
+ matcher.pattern ":app.:brand.com", :stage => 'production'
68
+ matcher.pattern ":app.:stage.:brand.com", :app => 'www', :brand => 'mmp', :stage => 'production'
69
+
70
+ assert_equal "www.mmp.com", matcher.generate
71
+ end
72
+
73
+ end
74
+
75
+ class MockPattern
76
+ attr_reader :got_match, :got_generate, :got_rewrite
77
+
78
+ def initialize(rval = false)
79
+ @rval = rval
80
+ end
81
+
82
+ def match(string)
83
+ @got_match = string
84
+ @rval
85
+ end
86
+
87
+ def generate(options)
88
+ @got_generate = options
89
+ @rval
90
+ end
91
+
92
+ def rewrite(string, options)
93
+ @got_rewrite = [string, options]
94
+ @rval
95
+ end
96
+ end
97
+ end
98
+
@@ -0,0 +1,83 @@
1
+
2
+ require 'test/unit'
3
+ require 'dns_guru'
4
+
5
+ module DnsGuru
6
+ class TestPattern < Test::Unit::TestCase
7
+
8
+ def test_initialize
9
+ p = Pattern.new(":blah.:blah")
10
+ assert_not_nil p, "Initialization should work"
11
+ end
12
+
13
+ def test_parse
14
+ p = Pattern.new(":blah.:blah")
15
+ segments = p.segments
16
+ assert !segments.empty?, "Parsing should return an array of segments"
17
+ end
18
+
19
+ def test_segment_types
20
+ p = Pattern.new(":blah.dev.:blah")
21
+ segments = p.segments
22
+ assert_kind_of DynamicSegment, segments.first, "First Segment should be Dynamic"
23
+ assert_kind_of StaticSegment, segments[1], "Second Segment should be Static"
24
+ end
25
+
26
+ def test_match
27
+ p = Pattern.new(":app.:stage.:brand.:tld")
28
+ assert_equal({ :app => 'www', :stage => 'dev', :brand => 'mmp', :tld => 'com' }, p.match("www.dev.mmp.com"))
29
+ assert_equal({ :app => 'www-01', :stage => 'dev', :brand => 'mmp', :tld => 'com' }, p.match("www-01.dev.mmp.com"))
30
+ end
31
+
32
+ def test_match_with_specified_hyphens
33
+ p = Pattern.new(":app.:stage-:machine.:brand.:tld")
34
+ assert_equal({ :app => 'www', :machine => '01', :stage => 'dev', :brand => 'mmp', :tld => 'com' }, p.match("www.dev-01.mmp.com"))
35
+ end
36
+
37
+ def test_match_with_static_segments
38
+ p = Pattern.new(":app.dev.:brand.:tld", :stage => 'development')
39
+ assert_equal({ :app => 'www', :stage => 'development', :brand => 'mmp', :tld => 'com' }, p.match("www.dev.mmp.com"))
40
+ end
41
+
42
+ def test_match_no_match
43
+ p = Pattern.new("foo")
44
+ assert_equal(nil, p.match("ausfark"))
45
+ end
46
+
47
+ def test_localhost
48
+ p = Pattern.new("localhost", :stage => 'development', :brand => 'mms', :tld => 'com', :app => 'www')
49
+ assert_equal({ :app => 'www', :stage => 'development', :brand => 'mms', :tld => 'com' }, p.match("localhost"))
50
+ end
51
+
52
+ def test_generate
53
+ p = Pattern.new(":app.:stage.:brand.:tld")
54
+ assert_equal "www.qa.mms.com", p.generate(:app => 'www', :stage => 'qa', :brand => 'mms', :tld => 'com')
55
+ end
56
+
57
+ def test_generate_with_defaults
58
+ p = Pattern.new(":app.:stage.:brand.:tld", :tld => 'com')
59
+ assert_equal "www.qa.mms.com", p.generate(:app => 'www', :stage => 'qa', :brand => 'mms')
60
+ end
61
+
62
+ def test_generate_with_statics
63
+ p = Pattern.new(":app.dev.:brand.:tld", :stage => 'development')
64
+ assert_equal "www.dev.mms.com", p.generate(:app => 'www', :stage => 'development', :brand => 'mms', :tld => 'com')
65
+ end
66
+
67
+ def test_generate_fails_for_insufficient_params
68
+ p = Pattern.new(":app.dev.:brand.:tld", :stage => 'development')
69
+ assert_equal nil, p.generate(:stage => 'development', :brand => 'mms', :tld => 'com')
70
+ end
71
+
72
+ def test_generate_fails_for_surplus_params
73
+ p = Pattern.new(":app.dev.:brand.:tld", :stage => 'development')
74
+ assert_equal nil, p.generate(:extra => 'foo', :app => 'www', :stage => 'development', :brand => 'mms', :tld => 'com')
75
+ end
76
+
77
+ def test_rewrite
78
+ p = Pattern.new(":app.:stage.:brand.:tld")
79
+ assert_equal "www.qa.mmp.com", p.rewrite("www.qa.google.com", :brand => 'mmp')
80
+ end
81
+
82
+ end
83
+ end
@@ -0,0 +1,30 @@
1
+
2
+ require 'test/unit'
3
+ require 'dns_guru'
4
+
5
+ module DnsGuru
6
+ class TestRequestMixin < Test::Unit::TestCase
7
+
8
+ def setup
9
+ DnsGuru.init(File.join(File.dirname(__FILE__), "../config.rb"))
10
+ @req = MockRequest.new
11
+ end
12
+
13
+ def test_canonical_host_name
14
+ @req.host = "www.production.mamapedia.com"
15
+ assert_equal "www.mamapedia.com", @req.canonical_host_name
16
+ end
17
+
18
+ def test_host_name_params
19
+ @req.host = "www.production.mamapedia.com"
20
+ assert_equal({:app => 'www', :stage => 'production', :brand => 'mamapedia', :tld => 'com'},
21
+ @req.host_name_params, "Wrong host name components derived from raw host name")
22
+ end
23
+ end
24
+
25
+
26
+ class MockRequest
27
+ include RequestMixin
28
+ attr_accessor :host
29
+ end
30
+ end
@@ -0,0 +1,28 @@
1
+
2
+ require 'test/unit'
3
+ require 'dns_guru'
4
+
5
+ class TestDnsGuru < Test::Unit::TestCase
6
+
7
+ def setup
8
+ DnsGuru.init(File.join(File.dirname(__FILE__), "config.rb"))
9
+ end
10
+
11
+ def test_match
12
+ assert_equal({:app => 'www', :stage => 'production', :brand => 'google', :tld => 'com'}, DnsGuru.match("www.google.com"))
13
+ end
14
+
15
+ def test_generate
16
+ assert_equal("www.google.com", DnsGuru.generate(:app => 'www', :stage => 'production', :brand => 'google', :tld => 'com'))
17
+ assert_equal("www.mmp.com", DnsGuru.generate)
18
+ end
19
+
20
+ def test_rewrite
21
+ assert_equal("www.mmp.com", DnsGuru.rewrite("www.google.com", :brand => 'mmp'))
22
+ assert_equal("www.mmp.com", DnsGuru.rewrite("www.production.mmp.com"))
23
+ assert_equal("mail.google.com", DnsGuru.rewrite("www.google.com", :app => 'mail'))
24
+ assert_equal("www.google.co.jp", DnsGuru.rewrite("www.google.com", :tld => 'co.jp')) # this is iffy
25
+ assert_equal(nil, DnsGuru.rewrite("www.google.com", :stage => 'asdf', :nuts => 'too'))
26
+ end
27
+
28
+ end
metadata ADDED
@@ -0,0 +1,69 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: dns_guru
3
+ version: !ruby/object:Gem::Version
4
+ version: "0.1"
5
+ platform: ruby
6
+ authors:
7
+ - Dns Guru
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2010-03-07 00:00:00 -08:00
13
+ default_executable:
14
+ dependencies: []
15
+
16
+ description:
17
+ email: ken.miller@gmail.com
18
+ executables: []
19
+
20
+ extensions: []
21
+
22
+ extra_rdoc_files:
23
+ - README
24
+ files:
25
+ - init.rb
26
+ - Rakefile
27
+ - README
28
+ - lib/dns_guru/controller_mixin.rb
29
+ - lib/dns_guru/matcher.rb
30
+ - lib/dns_guru/pattern.rb
31
+ - lib/dns_guru/request_mixin.rb
32
+ - lib/dns_guru.rb
33
+ - rails/init.rb
34
+ - test/config.rb
35
+ - test/dns_guru/test_controller_mixin.rb
36
+ - test/dns_guru/test_matcher.rb
37
+ - test/dns_guru/test_pattern.rb
38
+ - test/dns_guru/test_request_mixin.rb
39
+ - test/test_dns_guru.rb
40
+ has_rdoc: true
41
+ homepage: http://github.com/kemiller/dns_guru
42
+ licenses: []
43
+
44
+ post_install_message:
45
+ rdoc_options: []
46
+
47
+ require_paths:
48
+ - lib
49
+ required_ruby_version: !ruby/object:Gem::Requirement
50
+ requirements:
51
+ - - ">="
52
+ - !ruby/object:Gem::Version
53
+ version: "0"
54
+ version:
55
+ required_rubygems_version: !ruby/object:Gem::Requirement
56
+ requirements:
57
+ - - ">="
58
+ - !ruby/object:Gem::Version
59
+ version: "0"
60
+ version:
61
+ requirements: []
62
+
63
+ rubyforge_project:
64
+ rubygems_version: 1.3.5
65
+ signing_key:
66
+ specification_version: 3
67
+ summary: Parse hostnames into useful information with a routes-like syntax
68
+ test_files: []
69
+