ryodo 0.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -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