ryodo 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,19 @@
1
+ # encoding: utf-8
2
+
3
+ module Ryodo
4
+ module Convenience
5
+ module U
6
+
7
+ alias_method :ryodo, :Ryodo
8
+
9
+ # Unicode junkie? ;o)
10
+ alias_method :"ryōdo", :Ryodo
11
+ alias_method :"領土", :Ryodo
12
+ alias_method :"りょうど", :Ryodo
13
+
14
+ end
15
+
16
+ end
17
+ end
18
+
19
+ include Ryodo::Convenience::U
@@ -0,0 +1,13 @@
1
+ # encoding: utf-8
2
+
3
+ module Ryodo
4
+ module Convenience
5
+
6
+ def Ryodo(domain_string)
7
+ Ryodo.parse(domain_string)
8
+ end
9
+
10
+ end
11
+ end
12
+
13
+ include Ryodo::Convenience
@@ -0,0 +1,83 @@
1
+ # encoding: utf-8
2
+
3
+ module Ryodo
4
+ class Domain
5
+
6
+ # DomainString is a String with extended methods
7
+ class DomainString < String
8
+
9
+ def reverse
10
+ to_a(:r).join(".")
11
+ end
12
+ alias_method :r, :reverse
13
+
14
+ def to_a option = nil
15
+ case option
16
+ when :reverse, :r
17
+ dsplit.reverse
18
+ else
19
+ dsplit
20
+ end
21
+ end
22
+
23
+ private
24
+
25
+ def dsplit
26
+ self.split(".",-1)
27
+ end
28
+
29
+ end
30
+
31
+ # remove own class comparison (we will use String#== via method_missing)
32
+ undef_method :==
33
+
34
+ def initialize domainStr
35
+ raise TypeError, "Not a valid domain string!" unless domainStr.is_a?(String)
36
+ @domain_string = DomainString.new domainStr.downcase
37
+
38
+ parts = Ryodo::Parser.run(@domain_string)
39
+
40
+ @suffix = parts ? parts[0].reverse.join(".") : nil
41
+ @domain = parts && !parts[1].empty? ? (parts[0] + parts[1]).reverse.join(".") : nil
42
+ @subdomain = parts && !parts[2].empty? ? (parts[2]).reverse.join(".") : nil
43
+ end
44
+
45
+ def suffix
46
+ DomainString.new @suffix if @suffix
47
+ end
48
+ alias_method :tld, :suffix
49
+
50
+ def domain
51
+ DomainString.new @domain if @domain
52
+ end
53
+ alias_method :registered_domain, :domain
54
+ alias_method :regdomain, :domain
55
+
56
+ def subdomain
57
+ DomainString.new @subdomain if @subdomain
58
+ end
59
+
60
+ def fqdn
61
+ DomainString.new "#{to_s}."
62
+ end
63
+
64
+ def to_s
65
+ @domain_string
66
+ end
67
+
68
+ def inspect
69
+ @domain_string.inspect
70
+ end
71
+
72
+ # pass all missings to @domain_string (String class)
73
+ def method_missing(name, *args, &block)
74
+ @domain_string.send(name, *args, &block)
75
+ end
76
+
77
+ # explicit definition of class' send
78
+ def send(symbol, *args)
79
+ __send__(symbol, *args)
80
+ end
81
+
82
+ end
83
+ end
@@ -0,0 +1,9 @@
1
+ class String
2
+
3
+ def to_domain
4
+ Ryodo.parse self
5
+ end
6
+ alias_method :ryodo, :to_domain
7
+ alias_method :to_ryodo, :to_domain
8
+
9
+ end
@@ -0,0 +1,12 @@
1
+ # encoding: utf-8
2
+
3
+ module Ryodo
4
+ module Methods
5
+
6
+ def parse domain_string
7
+ Ryodo::Domain.new domain_string
8
+ end
9
+ alias_method :[], :parse
10
+
11
+ end
12
+ end
@@ -0,0 +1,37 @@
1
+ # encoding: utf-8
2
+
3
+ module Ryodo
4
+ class Parser
5
+
6
+ def initialize
7
+ @rules = Ryodo::RuleSet.new
8
+ end
9
+
10
+ def build_query domain
11
+ if domain.to_s[0] == "."
12
+ # FQDN in reversed order
13
+ domain.downcase[1..-1].split(".")
14
+ else
15
+ domain.downcase.split(".").reverse
16
+ end
17
+ end
18
+
19
+ def parse domain
20
+ @rules.match build_query(domain)
21
+ end
22
+
23
+ class << self
24
+
25
+ def run domain
26
+ instance.parse domain
27
+ end
28
+
29
+
30
+ def instance
31
+ @@instance ||= new
32
+ end
33
+
34
+ end
35
+
36
+ end
37
+ end
data/lib/ryodo/rule.rb ADDED
@@ -0,0 +1,15 @@
1
+ # encoding: utf-8
2
+
3
+ module Ryodo
4
+ class Rule < Struct.new(:exception, :stopOK, :children)
5
+
6
+ def has_children?
7
+ !children.empty?
8
+ end
9
+
10
+ def is_suffix?
11
+ stopOK
12
+ end
13
+
14
+ end
15
+ end
@@ -0,0 +1,77 @@
1
+ # encoding: utf-8
2
+
3
+ module Ryodo
4
+ class RuleSet
5
+
6
+ def initialize
7
+ @tree = {}
8
+ build!
9
+ end
10
+
11
+ def build!
12
+
13
+ Ryodo::SuffixList.list.each do |line|
14
+
15
+ line.each.with_index do |node_name, idx|
16
+
17
+ stopOK = node_name == line.last
18
+ exception = node_name[0] == "!"
19
+ node_name = node_name[1..-1] if exception
20
+ children = {}
21
+
22
+ node = Ryodo::Rule.new(exception, stopOK, children)
23
+
24
+ if idx > 0
25
+ end_idx = idx - 1
26
+ parent = select_rule(line[0..end_idx])
27
+ parent.children[node_name] = node unless parent.children[node_name]
28
+
29
+ else
30
+ @tree[node_name] = node unless @tree[node_name]
31
+ end
32
+
33
+ end
34
+
35
+ end
36
+
37
+ end
38
+
39
+ def select_rule(rule_path)
40
+
41
+ path = rule_path.dup
42
+
43
+ if current = path.pop
44
+
45
+ if path.empty?
46
+ @tree[current]
47
+
48
+ else
49
+ rule = select_rule(path)
50
+ rule.children[current] if rule
51
+ end
52
+
53
+ end
54
+
55
+ end
56
+
57
+ def match(path)
58
+ suffix, domain, match = [], [], nil
59
+
60
+ until match || path.empty?
61
+ match = select_rule(path) || select_rule(path.dup.fill("*",-1))
62
+ match = nil if match && !match.is_suffix?
63
+ domain.unshift path.pop
64
+ suffix = path
65
+ end
66
+
67
+ suffix.push(domain.shift) if match && !match.exception
68
+
69
+ # only if match has no children with domain and domain is present
70
+ if match && !match.children.keys.include?(domain[0]) && domain[0]
71
+ [ suffix, [domain.shift], domain ]
72
+ end
73
+
74
+ end
75
+
76
+ end
77
+ end
@@ -0,0 +1,57 @@
1
+ # encoding: utf-8
2
+
3
+ module Ryodo
4
+
5
+ class SuffixList
6
+ def initialize suffix_file = Ryodo::PUBLIC_SUFFIX_STORE
7
+ load_file(suffix_file)
8
+ end
9
+
10
+ def parse_data
11
+ # loads and converts to array
12
+ # "baz.bar.foo" => ["baz", "bar", "foo"]
13
+ File.readlines(@suffix_file).map{ |line| line.strip.split(".") }
14
+ end
15
+
16
+ def load_file suffix_file = Ryodo::PUBLIC_SUFFIX_STORE
17
+ @suffix_file = suffix_file
18
+ @suffix_data = parse_data
19
+ end
20
+
21
+ def list
22
+ @suffix_data
23
+ end
24
+
25
+ def inspect
26
+ "#<#{self.class} FILE:#{@suffix_file} ENTRIES:#{@suffix_data.size}>"
27
+ end
28
+
29
+ class << self
30
+
31
+ def SuffixList suffix_file = Ryodo::PUBLIC_SUFFIX_STORE
32
+ instance(suffix_file)
33
+ end
34
+
35
+ def reload suffix_file = Ryodo::PUBLIC_SUFFIX_STORE
36
+ instance.load_file(suffix_file) && true
37
+ end
38
+
39
+ def list
40
+ instance.list
41
+ end
42
+
43
+ def instance
44
+ @@instance ||= new
45
+ end
46
+
47
+ def inspect
48
+ instance.inspect
49
+ end
50
+
51
+ end
52
+
53
+ private_class_method :new
54
+
55
+ end
56
+
57
+ end
@@ -0,0 +1,54 @@
1
+ # encoding: utf-8
2
+
3
+ require "uri"
4
+ require "net/http"
5
+
6
+ module Ryodo
7
+
8
+ class FetchError < StandardError; end
9
+
10
+ class SuffixListFetcher
11
+
12
+ def initialize uri = Ryodo::PUBLIC_SUFFIX_DATA_URI, store = Ryodo::PUBLIC_SUFFIX_STORE
13
+ @uri = URI(uri)
14
+ @store = store
15
+ end
16
+
17
+ def fetch_data
18
+ res = Net::HTTP.get_response(@uri)
19
+ raise Ryodo::FetchError, "Could not fetch suffix data! (#{res})" unless res.is_a?(Net::HTTPSuccess)
20
+ @fetched_data = res.body.lines
21
+ end
22
+
23
+ def prepare_data
24
+ @prepared_data = @fetched_data.inject([]) do |acc, line|
25
+ next(acc) if line =~ /^\/\/|^\n/
26
+ dns_line = line.strip.
27
+ split(".").
28
+ reverse.
29
+ join(".") # "foo.bar.baz" => "baz.bar.foo"
30
+ acc << dns_line
31
+ end.sort
32
+ end
33
+
34
+ def save_data
35
+ File.open(Ryodo::PUBLIC_SUFFIX_STORE, "w") do |fh|
36
+ fh.write @prepared_data.join("\n")
37
+ end if @prepared_data
38
+ end
39
+
40
+ class << self
41
+ def fetch_and_save! uri = Ryodo::PUBLIC_SUFFIX_DATA_URI, store = Ryodo::PUBLIC_SUFFIX_STORE
42
+ fetcher = self.new uri, store
43
+ fetcher.fetch_data
44
+ fetcher.prepare_data
45
+ fetcher.save_data
46
+ true
47
+ rescue
48
+ false
49
+ end
50
+ end
51
+
52
+ end
53
+
54
+ end
data/lib/ryodo.rb ADDED
@@ -0,0 +1,29 @@
1
+ # encoding: utf-8
2
+
3
+ module Ryodo
4
+
5
+ VERSION_FILE = File.expand_path("../../VERSION", __FILE__)
6
+ VERSION = File.exist?(VERSION_FILE) ? File.read(VERSION_FILE) : "(could not find VERSION file)"
7
+
8
+ RYODO_ROOT = File.expand_path("../..", __FILE__)
9
+
10
+ PUBLIC_SUFFIX_DATA_URI = "http://mxr.mozilla.org/mozilla-central/source/netwerk/dns/effective_tld_names.dat?raw=1"
11
+ PUBLIC_SUFFIX_STORE = "#{RYODO_ROOT}/data/suffix.dat"
12
+
13
+ end
14
+
15
+ require "ryodo/domain"
16
+ require "ryodo/parser"
17
+ require "ryodo/rule"
18
+ require "ryodo/rule_set"
19
+ require "ryodo/suffix_list"
20
+
21
+ require "ryodo/methods"
22
+ require "ryodo/ext/string"
23
+
24
+ # Convenient shorthands
25
+ module Ryodo
26
+ extend Ryodo::Methods
27
+ require "ryodo/convenience"
28
+ require "ryodo/convenience/.u" unless Kernel.const_defined?("RYODO_NO_U") || ENV['RYODO_NO_U']
29
+ end