barx 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
data/lib/xri_parser.rb ADDED
@@ -0,0 +1,163 @@
1
+ module XriParser
2
+ class AuthorityParser
3
+ ## AuthorityParser.parse(xri) returns an AuthorityParser object
4
+ ## Pass in <false> as a second arg to parse a local (rootless) XRI
5
+ class <<self
6
+ def parse(xri, get_root=true)
7
+ AuthorityParser.new(xri, get_root)
8
+ end
9
+ end
10
+
11
+ attr_reader :root, :subsegments, :authority, :local, :query, :qxri
12
+ attr_accessor :path
13
+
14
+ def initialize(xri, get_root=true)
15
+ @root = String.new
16
+ @subsegments = Array.new
17
+ xri = xri.strip rescue nil
18
+ xri = xri_strip_scheme(xri) rescue nil
19
+ @qxri = xri
20
+ raise 'No XRI Received' if xri.nil? or xri.empty?
21
+ #get root
22
+ if get_root
23
+ gcs_chars = Regexp.escape("@=!+*()")
24
+ gcs_connectors = Regexp.escape("@=!+*")
25
+ dns_rgx = Regexp.new("\\A(\\$dns\\*[^#{gcs_chars}]+)([#{gcs_connectors}].*)\\z", true)
26
+ ## equivalent to: /\A(\$dns\*[^@=!\+\*\(\)]+)([@=!\+\*].*)\z/i
27
+ ip_rgx = Regexp.new("\\A(\\$ip\\*[^#{gcs_chars}]+)([#{gcs_connectors}].*)\\z", true)
28
+ ## equivalent to: /\A(\$ip\*[^@=!\+\*\(\)]+)([@=!\+\*].*)\z/i
29
+ simple_roots = [?=, ?@, ?!, ?+]
30
+ if simple_roots.include? xri[0]
31
+ @root = xri[0].chr
32
+ xri = xri[1..-1] # xri is now the rest of xri after the root
33
+ elsif xri[0,2] == '$('
34
+ paren = 0
35
+ pointer = 0
36
+
37
+ @root = '$'
38
+ xri = xri[1..-1]
39
+ xri.each_byte do |c|
40
+ paren += 1 if c == ?(
41
+ paren -= 1 if c == ?)
42
+ pointer += 1
43
+ @root << c.chr
44
+ break if paren.zero?
45
+ end
46
+
47
+ xri = xri[pointer..-1] # xri is now the rest of xri after the root
48
+ elsif xri =~ dns_rgx
49
+ @root = $1
50
+ xri = $2
51
+ elsif xri =~ ip_rgx
52
+ @root = $1
53
+ xri = $2
54
+ else
55
+ raise XRIRootMissing, 'No XRI root'
56
+ end
57
+ end
58
+
59
+ if xri.length < 1
60
+ return true
61
+ end
62
+ if (@root == '!') and (xri[0] != ?!)
63
+ raise 'XRIs in the ! registry must start with !'
64
+ end
65
+
66
+ subsegment_delimiters = [?@, ?=, ?!, ?+, ?*]
67
+ #add implicit * after root if neccessary
68
+ xri.insert(0,'*') unless subsegment_delimiters.include? xri[0]
69
+ open_paren = 0
70
+ close_paren = 0
71
+ segment_buf = String.new
72
+
73
+ # get subsegments
74
+ xri.each_byte do |c|
75
+ open_paren += 1 if c == ?(
76
+ close_paren += 1 if c == ?)
77
+ # if we're inside an xref keep adding to buffer
78
+ if (open_paren > 0) and (open_paren != close_paren)
79
+ segment_buf << c.chr
80
+ next
81
+ end
82
+ # starting a new subsegment
83
+ if subsegment_delimiters.include? c
84
+ # flush the buffer
85
+ @subsegments << segment_buf unless segment_buf.empty?
86
+ # initialize a new buffer
87
+ segment_buf = ""
88
+ # add the delimiter to the buffer
89
+ segment_buf << c.chr
90
+ elsif (c == ?/) or (c == ??) or (c == ?#) #end of authority parsing
91
+ break
92
+ else
93
+ # add the character to the buffer
94
+ segment_buf << c.chr
95
+ end
96
+ end
97
+
98
+ @subsegments << segment_buf # flush buffer at the end
99
+ @local = xri[@subsegments.to_s.length..-1] # the rest of xri
100
+ @path = @local.index('?') ? @local[/^(.*)\?/, 1] : @local # path is everything up to a question mark
101
+ @query = @local.index('?') ? @local[/\?(.*)$/, 1] : '' # query is everything after a question mark
102
+ @authority = self.normalized
103
+ true
104
+ end
105
+
106
+ def xri_strip_scheme(xri)
107
+ if xri[0..5] =~ /xri:\/\//i
108
+ xri[6..-1]
109
+ elsif xri[0..3] =~ /xri:/i
110
+ xri[4..-1]
111
+ else
112
+ xri
113
+ end
114
+ end
115
+
116
+ def is_inumber?
117
+ @subsegments.each {|seg| return false if seg[0] != ?!}
118
+ true
119
+ end
120
+
121
+ def community
122
+ all_but_last_seg = @subsegments[0..-2].to_s
123
+ # strip off leading * if i-name and root is = or @
124
+ if @root == '@' or @root == '='
125
+ all_but_last_seg = all_but_last_seg[1..-1] if all_but_last_seg[0] == ?*
126
+ end
127
+ unless all_but_last_seg.nil? or all_but_last_seg.empty?
128
+ @root + all_but_last_seg
129
+ else
130
+ @root
131
+ end
132
+ end
133
+
134
+ def local_iname
135
+ unless self.is_inumber?
136
+ if @subsegments.last[0] == ?* # strip off leading * on local i-name
137
+ @subsegments.last[1..-1]
138
+ else
139
+ @subsegments.last
140
+ end
141
+ end
142
+ end
143
+
144
+ def local_inumber
145
+ @subsegments.last[0..-1] if self.is_inumber?
146
+ end
147
+
148
+ def fully_qualified
149
+ @root + @subsegments.to_s
150
+ end
151
+
152
+ def normalized
153
+ if @root == '@' or @root == '='
154
+ @root + @subsegments.to_s[1..-1]
155
+ else
156
+ @root + @subsegments.to_s
157
+ end
158
+ end
159
+
160
+ end
161
+
162
+ class XRIRootMissing < RuntimeError; end
163
+ end