wwmd 0.2.20.3
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.
- data/History.txt +38 -0
- data/README.rdoc +87 -0
- data/Rakefile +33 -0
- data/examples/config_example.yaml +24 -0
- data/examples/wwmd_example.rb +73 -0
- data/lib/wwmd.rb +84 -0
- data/lib/wwmd/class_extensions.rb +4 -0
- data/lib/wwmd/class_extensions/extensions_base.rb +251 -0
- data/lib/wwmd/class_extensions/extensions_encoding.rb +79 -0
- data/lib/wwmd/class_extensions/extensions_external.rb +18 -0
- data/lib/wwmd/class_extensions/extensions_nilclass.rb +11 -0
- data/lib/wwmd/class_extensions/extensions_rbkb.rb +193 -0
- data/lib/wwmd/class_extensions/mixins_string_encoding.rb +40 -0
- data/lib/wwmd/guid.rb +155 -0
- data/lib/wwmd/page.rb +3 -0
- data/lib/wwmd/page/_fa.old +302 -0
- data/lib/wwmd/page/auth.rb +17 -0
- data/lib/wwmd/page/constants.rb +63 -0
- data/lib/wwmd/page/form.rb +99 -0
- data/lib/wwmd/page/form_array.rb +304 -0
- data/lib/wwmd/page/headers.rb +118 -0
- data/lib/wwmd/page/helpers.rb +41 -0
- data/lib/wwmd/page/html2text_hpricot.rb +76 -0
- data/lib/wwmd/page/html2text_nokogiri.rb +42 -0
- data/lib/wwmd/page/inputs.rb +47 -0
- data/lib/wwmd/page/irb_helpers.rb +114 -0
- data/lib/wwmd/page/page.rb +257 -0
- data/lib/wwmd/page/parsing_convenience.rb +98 -0
- data/lib/wwmd/page/reporting_helpers.rb +89 -0
- data/lib/wwmd/page/scrape.rb +196 -0
- data/lib/wwmd/page/spider.rb +127 -0
- data/lib/wwmd/urlparse.rb +125 -0
- data/lib/wwmd/viewstate.rb +17 -0
- data/lib/wwmd/viewstate/viewstate.rb +101 -0
- data/lib/wwmd/viewstate/viewstate_deserializer_methods.rb +217 -0
- data/lib/wwmd/viewstate/viewstate_from_xml.rb +129 -0
- data/lib/wwmd/viewstate/viewstate_types.rb +51 -0
- data/lib/wwmd/viewstate/viewstate_utils.rb +164 -0
- data/lib/wwmd/viewstate/viewstate_yaml.rb +25 -0
- data/lib/wwmd/viewstate/vs_stubs.rb +22 -0
- data/lib/wwmd/viewstate/vs_stubs/vs_array.rb +38 -0
- data/lib/wwmd/viewstate/vs_stubs/vs_binary_serialized.rb +30 -0
- data/lib/wwmd/viewstate/vs_stubs/vs_hashtable.rb +42 -0
- data/lib/wwmd/viewstate/vs_stubs/vs_hybrid_dict.rb +42 -0
- data/lib/wwmd/viewstate/vs_stubs/vs_indexed_string.rb +6 -0
- data/lib/wwmd/viewstate/vs_stubs/vs_indexed_string_ref.rb +24 -0
- data/lib/wwmd/viewstate/vs_stubs/vs_int_enum.rb +27 -0
- data/lib/wwmd/viewstate/vs_stubs/vs_list.rb +34 -0
- data/lib/wwmd/viewstate/vs_stubs/vs_pair.rb +29 -0
- data/lib/wwmd/viewstate/vs_stubs/vs_read_types.rb +11 -0
- data/lib/wwmd/viewstate/vs_stubs/vs_read_value.rb +35 -0
- data/lib/wwmd/viewstate/vs_stubs/vs_sparse_array.rb +58 -0
- data/lib/wwmd/viewstate/vs_stubs/vs_string.rb +33 -0
- data/lib/wwmd/viewstate/vs_stubs/vs_string_array.rb +39 -0
- data/lib/wwmd/viewstate/vs_stubs/vs_string_formatted.rb +32 -0
- data/lib/wwmd/viewstate/vs_stubs/vs_stub_helpers.rb +37 -0
- data/lib/wwmd/viewstate/vs_stubs/vs_triplet.rb +31 -0
- data/lib/wwmd/viewstate/vs_stubs/vs_type.rb +23 -0
- data/lib/wwmd/viewstate/vs_stubs/vs_unit.rb +30 -0
- data/lib/wwmd/viewstate/vs_stubs/vs_value.rb +35 -0
- data/lib/wwmd/wwmd_config.rb +52 -0
- data/lib/wwmd/wwmd_puts.rb +9 -0
- data/lib/wwmd/wwmd_utils.rb +28 -0
- data/spec/README +3 -0
- data/spec/form_array.spec +49 -0
- data/spec/spider_csrf_test.spec +28 -0
- data/spec/urlparse_test.spec +101 -0
- data/tasks/ann.rake +80 -0
- data/tasks/bones.rake +20 -0
- data/tasks/gem.rake +201 -0
- data/tasks/git.rake +40 -0
- data/tasks/notes.rake +27 -0
- data/tasks/post_load.rake +34 -0
- data/tasks/rdoc.rake +51 -0
- data/tasks/rubyforge.rake +55 -0
- data/tasks/setup.rb +292 -0
- data/tasks/spec.rake +54 -0
- data/tasks/test.rake +40 -0
- data/tasks/zentest.rake +36 -0
- metadata +222 -0
@@ -0,0 +1,79 @@
|
|
1
|
+
require 'wwmd/class_extensions/mixins_string_encoding'
|
2
|
+
class String
|
3
|
+
include WWMD::Encoding
|
4
|
+
|
5
|
+
@@he = HTMLEntities.new
|
6
|
+
|
7
|
+
# base 64 decode
|
8
|
+
def b64d
|
9
|
+
self.unpack("m").first
|
10
|
+
end
|
11
|
+
|
12
|
+
# base 64 encode
|
13
|
+
def b64e
|
14
|
+
[self].pack("m").gsub("\n","")
|
15
|
+
end
|
16
|
+
|
17
|
+
# URI.escape using defaults or passed regexp
|
18
|
+
def escape(reg=nil,unicodify=false)
|
19
|
+
if reg.nil?
|
20
|
+
ret = URI.escape(self)
|
21
|
+
elsif reg.kind_of?(Symbol)
|
22
|
+
case reg
|
23
|
+
when :none; return self
|
24
|
+
when :default; ret = URI.escape(self)
|
25
|
+
else; ret = URI.escape(self,WWMD::ESCAPE[reg])
|
26
|
+
end
|
27
|
+
else
|
28
|
+
ret = URI.escape(self,reg)
|
29
|
+
end
|
30
|
+
if unicodify
|
31
|
+
ret.gsub!(/%/,"%u00")
|
32
|
+
end
|
33
|
+
return ret
|
34
|
+
end
|
35
|
+
|
36
|
+
# URI.escape
|
37
|
+
def escape_url(reg=WWMD::ESCAPE[:url])#:nodoc:
|
38
|
+
self.escape(reg)
|
39
|
+
end
|
40
|
+
|
41
|
+
def escape_xss(reg=WWMD::ESCAPE[:xss])#:nodoc:
|
42
|
+
self.escape(reg)
|
43
|
+
end
|
44
|
+
|
45
|
+
def escape_default(reg=WWMD::ESCAPE[:default])
|
46
|
+
self.escape(reg)
|
47
|
+
end
|
48
|
+
# URI.escape all characters in string
|
49
|
+
def escape_all#:nodoc:
|
50
|
+
self.escape(/.*/)
|
51
|
+
end
|
52
|
+
|
53
|
+
# URI.unescape
|
54
|
+
def unescape
|
55
|
+
URI.unescape(self)
|
56
|
+
end
|
57
|
+
|
58
|
+
# html entity encode string
|
59
|
+
# sym = :basic :named :decimal :hexadecimal
|
60
|
+
def eencode(sym=nil)
|
61
|
+
sym = :named if sym.nil?
|
62
|
+
@@he.encode(self,sym)
|
63
|
+
end
|
64
|
+
|
65
|
+
# decode html entities in string
|
66
|
+
def edecode
|
67
|
+
return @@he.decode(self)
|
68
|
+
end
|
69
|
+
|
70
|
+
# quoted printable
|
71
|
+
def to_qp
|
72
|
+
[self].pack("M")
|
73
|
+
end
|
74
|
+
|
75
|
+
def from_qp
|
76
|
+
self.unpack("M").first
|
77
|
+
end
|
78
|
+
|
79
|
+
end
|
@@ -0,0 +1,11 @@
|
|
1
|
+
# I really hate this
|
2
|
+
class NilClass#:nodoc:
|
3
|
+
def empty?; return true; end
|
4
|
+
def size; return 0; end
|
5
|
+
def to_form; return FormArray.new([]); end
|
6
|
+
def clop; return nil; end
|
7
|
+
def inner_html; return nil; end
|
8
|
+
def get_attribute(*args); return nil; end
|
9
|
+
def grep(*args); return []; end
|
10
|
+
def escape(*args); return nil; end
|
11
|
+
end
|
@@ -0,0 +1,193 @@
|
|
1
|
+
# Author Eric Monti (emonti@matasano.com)
|
2
|
+
require "base64"
|
3
|
+
require "stringio"
|
4
|
+
require 'zlib'
|
5
|
+
require 'open3'
|
6
|
+
require 'sha1'
|
7
|
+
|
8
|
+
HEXCHARS = [("0".."9").to_a, ("a".."f").to_a].flatten unless defined?(HEXCHARS)
|
9
|
+
|
10
|
+
#-----------------------------------------------------------------------------
|
11
|
+
# Mixins and class-specific items
|
12
|
+
|
13
|
+
class Fixnum#:nodoc:
|
14
|
+
def to_l32; [self].pack "L"; end
|
15
|
+
def to_b32; [self].pack "N"; end
|
16
|
+
def to_l16; [self].pack "v"; end
|
17
|
+
def to_b16; [self].pack "n"; end
|
18
|
+
def to_u8; [self].pack "C"; end
|
19
|
+
def to_l8; chr; end
|
20
|
+
def to_n8; chr; end
|
21
|
+
alias to_n32 to_b32
|
22
|
+
alias to_n16 to_b16
|
23
|
+
def to_n32; [self].pack "N"; end
|
24
|
+
def to_n16; [self].pack "n"; end
|
25
|
+
|
26
|
+
def self.from_l8(str); str[0]; end
|
27
|
+
def self.from_l16(str); (str.unpack "v")[0]; end
|
28
|
+
def self.from_l32(str); (str.unpack "V")[0]; end
|
29
|
+
def self.from_n8(str); str[0]; end
|
30
|
+
def self.from_n16(str); (str.unpack "n")[0]; end
|
31
|
+
def self.from_n32(str); (str.unpack "N")[0]; end
|
32
|
+
end
|
33
|
+
|
34
|
+
class String
|
35
|
+
|
36
|
+
# shortcut for hex sanity with regex
|
37
|
+
def ishex? ; (self =~ /^[a-f0-9]+$/i)? true : false ; end
|
38
|
+
|
39
|
+
=begin
|
40
|
+
# Convert a string to ASCII hex string
|
41
|
+
# supports a few options for format:
|
42
|
+
# :delim - delimter between each hex byte
|
43
|
+
# :prefix - prefix before each hex byte
|
44
|
+
# :suffix - suffix after each hex byte
|
45
|
+
#
|
46
|
+
def hexify(opts={})
|
47
|
+
s=self
|
48
|
+
delim = opts[:delim]
|
49
|
+
pre = (opts[:prefix] || "")
|
50
|
+
suf = (opts[:suffix] || "")
|
51
|
+
|
52
|
+
if (rx=opts[:rx]) and not rx.kind_of? Regexp
|
53
|
+
raise "rx must be a regular expression for a character class"
|
54
|
+
end
|
55
|
+
|
56
|
+
out=Array.new
|
57
|
+
|
58
|
+
s.each_byte do |c|
|
59
|
+
hc = if (rx and not rx.match c.chr)
|
60
|
+
c.chr
|
61
|
+
else
|
62
|
+
pre + (HEXCHARS[(c >> 4)] + HEXCHARS[(c & 0xf )]) + suf
|
63
|
+
end
|
64
|
+
out << (hc)
|
65
|
+
end
|
66
|
+
out.join(delim)
|
67
|
+
end
|
68
|
+
|
69
|
+
|
70
|
+
# Convert ASCII hex string to raw
|
71
|
+
# supports only 'delimiter' between hex bytes
|
72
|
+
def unhexify(d=/\s*/)
|
73
|
+
s=self.strip
|
74
|
+
out=StringIO.new
|
75
|
+
while m = s.match(/^([A-Fa-f0-9]{1,2})#{d}?/) do
|
76
|
+
out.write m[1].hex.chr
|
77
|
+
s = m.post_match
|
78
|
+
end
|
79
|
+
out.string
|
80
|
+
end
|
81
|
+
alias_method :dehexify, :unhexify
|
82
|
+
=end
|
83
|
+
|
84
|
+
# ==========================================================================
|
85
|
+
# Extends String class to return a hexdump in the style of 'hexdump -C'
|
86
|
+
#
|
87
|
+
# :len => optionally specify a length other than 16 for a wider or thinner
|
88
|
+
# dump. If length is an odd number, it will be rounded up.
|
89
|
+
#
|
90
|
+
# :out => optionally specify an alternate IO object for output. By default,
|
91
|
+
# hexdump will output to STDOUT. Pass a StringIO object and it will return
|
92
|
+
# it as a string.
|
93
|
+
#
|
94
|
+
# Example:
|
95
|
+
# xxd = dat.hexdump(:len => 16, :out => StringIO.new)
|
96
|
+
# xxd => a hexdump
|
97
|
+
#
|
98
|
+
# xxd = dat.hexdump(:len => 16, :out => STDERR)
|
99
|
+
# xxd => nil
|
100
|
+
# ==========================================================================
|
101
|
+
def hexdump(opt={})
|
102
|
+
s=self
|
103
|
+
out = opt[:out] || StringIO.new
|
104
|
+
len = (opt[:len] and opt[:len] > 0)? opt[:len] + (opt[:len] % 2) : 16
|
105
|
+
|
106
|
+
off = opt[:start_addr] || 0
|
107
|
+
offlen = opt[:start_len] || 8
|
108
|
+
|
109
|
+
hlen=len/2
|
110
|
+
|
111
|
+
s.scan(/(?:.|\n){1,#{len}}/) do |m|
|
112
|
+
out.write(off.to_s(16).rjust(offlen, "0") + ' ')
|
113
|
+
|
114
|
+
i=0
|
115
|
+
m.each_byte do |c|
|
116
|
+
out.write c.to_s(16).rjust(2,"0") + " "
|
117
|
+
out.write(' ') if (i+=1) == hlen
|
118
|
+
end
|
119
|
+
|
120
|
+
out.write(" " * (len-i) ) # pad
|
121
|
+
out.write(" ") if i < hlen
|
122
|
+
|
123
|
+
out.write(" |" + m.tr("\0-\37\177-\377", '.') + "|\n")
|
124
|
+
off += m.length
|
125
|
+
end
|
126
|
+
|
127
|
+
out.write(off.to_s(16).rjust(offlen,'0') + "\n")
|
128
|
+
|
129
|
+
if out.class == StringIO
|
130
|
+
out.string
|
131
|
+
end
|
132
|
+
end
|
133
|
+
|
134
|
+
def hdp
|
135
|
+
puts hexdump
|
136
|
+
end
|
137
|
+
|
138
|
+
# ==========================================================================
|
139
|
+
# converts a hexdump back to binary - takes the same options as hexdump()
|
140
|
+
# fairly flexible. should work both with 'xxd' and 'hexdump -C' style dumps
|
141
|
+
def dehexdump(opt={})
|
142
|
+
s=self
|
143
|
+
out = opt[:out] || StringIO.new
|
144
|
+
len = (opt[:len] and opt[:len] > 0)? opt[:len] : 16
|
145
|
+
|
146
|
+
hcrx = /[A-Fa-f0-9]/
|
147
|
+
dumprx = /^(#{hcrx}+):?\s*((?:#{hcrx}{2}\s*){0,#{len}})/
|
148
|
+
off = opt[:start_addr] || 0
|
149
|
+
|
150
|
+
i=1
|
151
|
+
# iterate each line of hexdump
|
152
|
+
s.split(/\r?\n/).each do |hl|
|
153
|
+
# match and check offset
|
154
|
+
if m = dumprx.match(hl) and $1.hex == off
|
155
|
+
i+=1
|
156
|
+
# take the data chunk and unhexify it
|
157
|
+
raw = $2.unhexify
|
158
|
+
off += out.write(raw)
|
159
|
+
else
|
160
|
+
raise "Hexdump parse error on line #{i} #{s}"
|
161
|
+
end
|
162
|
+
end
|
163
|
+
|
164
|
+
if out.class == StringIO
|
165
|
+
out.string
|
166
|
+
end
|
167
|
+
end
|
168
|
+
alias_method :dedump, :dehexdump
|
169
|
+
|
170
|
+
# Does string "start with" dat?
|
171
|
+
# no clue whether/when this is faster than a regex, but it is easier
|
172
|
+
# than escaping regex characters
|
173
|
+
def starts_with?(dat)
|
174
|
+
self[0,dat.size] == dat
|
175
|
+
end
|
176
|
+
|
177
|
+
# returns CRC32 checksum for the string object
|
178
|
+
def crc32
|
179
|
+
Zlib.crc32 self
|
180
|
+
end
|
181
|
+
|
182
|
+
def swap16; unpack("v*").pack("n*"); end
|
183
|
+
def to_utf16; Kconv.kconv(self, NKF::UTF16, NKF::ASCII).swap16; end
|
184
|
+
def to_ascii; Kconv.kconv(swap16, NKF::ASCII, NKF::UTF16); end
|
185
|
+
|
186
|
+
end # class String
|
187
|
+
|
188
|
+
|
189
|
+
class Float
|
190
|
+
def log2; Math.log(self)/Math.log(2); end
|
191
|
+
end
|
192
|
+
|
193
|
+
__END__
|
@@ -0,0 +1,40 @@
|
|
1
|
+
=begin rdoc
|
2
|
+
Place methods to character encodings here
|
3
|
+
=end
|
4
|
+
|
5
|
+
module WWMD
|
6
|
+
# This is where character encodings should go as module methods
|
7
|
+
# to be used as mixins for the String class
|
8
|
+
module Encoding
|
9
|
+
|
10
|
+
# String.to_utf7 mixin
|
11
|
+
# (complete hack but it works)
|
12
|
+
#
|
13
|
+
# if all=true, encode all characters.
|
14
|
+
# if all.class=Regexp encode only characters in the passed
|
15
|
+
# regular expression else default to /[^0-9a-zA-Z]/
|
16
|
+
#
|
17
|
+
# used by:
|
18
|
+
# String.to_utf7
|
19
|
+
# String.to_utf7!
|
20
|
+
def to_utf7(all=nil)
|
21
|
+
if all.kind_of?(Regexp)
|
22
|
+
reg = all
|
23
|
+
elsif all.kind_of?(TrueClass)
|
24
|
+
reg = ESCAPE[:all]
|
25
|
+
else
|
26
|
+
reg = ESCAPE[:nalnum] || /[^a-zA-Z0-9]/
|
27
|
+
end
|
28
|
+
putd "DEBG:" + reg.inspect
|
29
|
+
ret = ''
|
30
|
+
self.each_byte do |b|
|
31
|
+
if b.chr.match(reg)
|
32
|
+
ret += "+" + Base64.encode64(b.chr.toutf16)[0..2] + "-"
|
33
|
+
else
|
34
|
+
ret += b.chr
|
35
|
+
end
|
36
|
+
end
|
37
|
+
return ret
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
data/lib/wwmd/guid.rb
ADDED
@@ -0,0 +1,155 @@
|
|
1
|
+
=begin rdoc
|
2
|
+
Guid - Ruby library for portable GUID/UUID generation.
|
3
|
+
|
4
|
+
Copyright (c) 2004 David Garamond <davegaramond at icqmail com>
|
5
|
+
|
6
|
+
This library is free software; you can redistribute it and/or modify it
|
7
|
+
under the same terms as Ruby itself.
|
8
|
+
|
9
|
+
(small hack to fix for mac mtracy@matasano.com)
|
10
|
+
=end
|
11
|
+
|
12
|
+
if RUBY_PLATFORM =~ /win/i && ! RUBY_PLATFORM =~ /darwin/i
|
13
|
+
module Guid_Win32_#:nodoc:
|
14
|
+
require 'Win32API'
|
15
|
+
|
16
|
+
PROV_RSA_FULL = 1
|
17
|
+
CRYPT_VERIFYCONTEXT = 0xF0000000
|
18
|
+
FORMAT_MESSAGE_IGNORE_INSERTS = 0x00000200
|
19
|
+
FORMAT_MESSAGE_FROM_SYSTEM = 0x00001000
|
20
|
+
|
21
|
+
CryptAcquireContext = Win32API.new("advapi32", "CryptAcquireContext",
|
22
|
+
'PPPII', 'L')
|
23
|
+
CryptGenRandom = Win32API.new("advapi32", "CryptGenRandom",
|
24
|
+
'LIP', 'L')
|
25
|
+
CryptReleaseContext = Win32API.new("advapi32", "CryptReleaseContext",
|
26
|
+
'LI', 'L')
|
27
|
+
GetLastError = Win32API.new("kernel32", "GetLastError", '', 'L')
|
28
|
+
FormatMessageA = Win32API.new("kernel32", "FormatMessageA",
|
29
|
+
'LPLLPLPPPPPPPP', 'L')
|
30
|
+
|
31
|
+
def lastErrorMessage
|
32
|
+
code = GetLastError.call
|
33
|
+
msg = "\0" * 1024
|
34
|
+
len = FormatMessageA.call(FORMAT_MESSAGE_IGNORE_INSERTS +
|
35
|
+
FORMAT_MESSAGE_FROM_SYSTEM, 0,
|
36
|
+
code, 0, msg, 1024, nil, nil,
|
37
|
+
nil, nil, nil, nil, nil, nil)
|
38
|
+
msg[0, len].tr("\r", '').chomp
|
39
|
+
end
|
40
|
+
|
41
|
+
def initialize
|
42
|
+
hProvStr = " " * 4
|
43
|
+
if CryptAcquireContext.call(hProvStr, nil, nil, PROV_RSA_FULL,
|
44
|
+
CRYPT_VERIFYCONTEXT) == 0
|
45
|
+
raise SystemCallError, "CryptAcquireContext failed: #{lastErrorMessage}"
|
46
|
+
end
|
47
|
+
hProv, = hProvStr.unpack('L')
|
48
|
+
@bytes = " " * 16
|
49
|
+
if CryptGenRandom.call(hProv, 16, @bytes) == 0
|
50
|
+
raise SystemCallError, "CryptGenRandom failed: #{lastErrorMessage}"
|
51
|
+
end
|
52
|
+
if CryptReleaseContext.call(hProv, 0) == 0
|
53
|
+
raise SystemCallError, "CryptReleaseContext failed: #{lastErrorMessage}"
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
module Guid_Unix_#:nodoc:
|
60
|
+
@@random_device = nil
|
61
|
+
|
62
|
+
def initialize
|
63
|
+
if !@@random_device
|
64
|
+
if File.exists? "/dev/urandom"
|
65
|
+
@@random_device = File.open "/dev/urandom", "r"
|
66
|
+
elsif File.exists? "/dev/random"
|
67
|
+
@@random_device = File.open "/dev/random", "r"
|
68
|
+
else
|
69
|
+
raise RuntimeError, "Can't find random device"
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
@bytes = @@random_device.read(16)
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
class Guid
|
78
|
+
if RUBY_PLATFORM =~ /win/ && ! RUBY_PLATFORM =~ /darwin/i
|
79
|
+
include Guid_Win32_
|
80
|
+
else
|
81
|
+
include Guid_Unix_
|
82
|
+
end
|
83
|
+
|
84
|
+
def hexdigest
|
85
|
+
@bytes.unpack("h*")[0]
|
86
|
+
end
|
87
|
+
|
88
|
+
def to_s
|
89
|
+
@bytes.unpack("h8 h4 h4 h4 h12").join "-"
|
90
|
+
end
|
91
|
+
|
92
|
+
def inspect
|
93
|
+
to_s
|
94
|
+
end
|
95
|
+
|
96
|
+
def raw
|
97
|
+
@bytes
|
98
|
+
end
|
99
|
+
|
100
|
+
def self.from_s(s)
|
101
|
+
raise ArgumentError, "Invalid GUID hexstring" unless
|
102
|
+
s =~ /\A[0-9a-f]{8}-?[0-9a-f]{4}-?[0-9a-f]{4}-?[0-9a-f]{4}-?[0-9a-f]{12}\z/i
|
103
|
+
guid = Guid.allocate
|
104
|
+
guid.instance_eval { @bytes = [s.gsub(/[^0-9a-f]+/i, '')].pack "h*" }
|
105
|
+
guid
|
106
|
+
end
|
107
|
+
|
108
|
+
def self.from_raw(bytes)
|
109
|
+
raise ArgumentError, "Invalid GUID raw bytes, length must be 16 bytes" unless
|
110
|
+
bytes.length == 16
|
111
|
+
guid = Guid.allocate
|
112
|
+
guid.instance_eval { @bytes = bytes }
|
113
|
+
guid
|
114
|
+
end
|
115
|
+
|
116
|
+
def ==(other)
|
117
|
+
@bytes == other.raw
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
121
|
+
if __FILE__ == $0
|
122
|
+
require 'test/unit'
|
123
|
+
|
124
|
+
class GuidTest < Test::Unit::TestCase#:nodoc:
|
125
|
+
def test_new
|
126
|
+
g = Guid.new
|
127
|
+
|
128
|
+
# different representations of guid: hexdigest, hex+dashes, raw bytes
|
129
|
+
assert_equal(0, g.to_s =~ /\A[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}\z/)
|
130
|
+
assert_equal(16, g.raw.length)
|
131
|
+
assert_equal(0, g.hexdigest =~ /\A[0-9a-f]{32}\z/)
|
132
|
+
assert_equal(g.hexdigest, g.to_s.gsub(/-/, ''))
|
133
|
+
|
134
|
+
# must be different each time we produce (this is just a simple test)
|
135
|
+
g2 = Guid.new
|
136
|
+
assert_equal(true, g != g2)
|
137
|
+
assert_equal(true, g.to_s != g2.to_s)
|
138
|
+
assert_equal(true, g.raw != g2.raw)
|
139
|
+
assert_equal(true, g.hexdigest != g2.hexdigest)
|
140
|
+
assert_equal(1000, (1..1000).select { |i| g != Guid.new }.length)
|
141
|
+
end
|
142
|
+
|
143
|
+
def test_from_s
|
144
|
+
g = Guid.new
|
145
|
+
g2 = Guid.from_s(g.to_s)
|
146
|
+
assert_equal(g, g2)
|
147
|
+
end
|
148
|
+
|
149
|
+
def test_from_raw
|
150
|
+
g = Guid.new
|
151
|
+
g2 = Guid.from_raw(g.raw)
|
152
|
+
assert_equal(g, g2)
|
153
|
+
end
|
154
|
+
end
|
155
|
+
end
|