maca-rosc 0.0.1
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/AUTHORS +11 -0
- data/ChangeLog +6 -0
- data/GPL.txt +340 -0
- data/History.txt +4 -0
- data/LICENSE +57 -0
- data/Manifest.txt +22 -0
- data/PostInstall.txt +7 -0
- data/README +55 -0
- data/README.rdoc +55 -0
- data/Rakefile +29 -0
- data/TODO +3 -0
- data/examples/readme.rb +19 -0
- data/lib/osc.rb +327 -0
- data/lib/osc/pattern.rb +131 -0
- data/lib/osc/server.rb +94 -0
- data/lib/osc/transport.rb +42 -0
- data/lib/osc/udp.rb +30 -0
- data/lib/rosc.rb +8 -0
- data/script/console +10 -0
- data/script/destroy +14 -0
- data/script/generate +14 -0
- data/test/test_osc.rb +160 -0
- metadata +99 -0
data/lib/osc/pattern.rb
ADDED
@@ -0,0 +1,131 @@
|
|
1
|
+
require 'set'
|
2
|
+
module OSC
|
3
|
+
class Pattern < String
|
4
|
+
# Create an OSC pattern from a string or (experimental) from a Regex.
|
5
|
+
def initialize(s)
|
6
|
+
case s
|
7
|
+
when Regexp # This is experimental
|
8
|
+
s = Regexp.source s
|
9
|
+
s.gsub! /(\\\\)*\[^\/\]\*/, "\1*"
|
10
|
+
s.gsub! /(\\\\)*\[^\/\]/, "\1?"
|
11
|
+
s.gsub! /(\\\\)*\[^/, "\1[!"
|
12
|
+
s.gsub! /(\\\\)*\(/, "\1{"
|
13
|
+
s.gsub! /(\\\\)*\|/, "\1,"
|
14
|
+
s.gsub! /(\\\\)*\)/, "\1}"
|
15
|
+
s.gsub! /\\\\/, "\\"
|
16
|
+
end
|
17
|
+
super s
|
18
|
+
end
|
19
|
+
|
20
|
+
# Return a Regex representing this pattern
|
21
|
+
def regexp
|
22
|
+
s = Regexp.escape self
|
23
|
+
s.gsub! /\\\?/, '[^/]'
|
24
|
+
s.gsub! /\\\*/, '[^/]*'
|
25
|
+
s.gsub! /\\\[!/, '[^'
|
26
|
+
s.gsub! /\\\]/, ']'
|
27
|
+
s.gsub! /\\\{/, '('
|
28
|
+
s.gsub! /,/, '|'
|
29
|
+
s.gsub! /\\\}/, ')'
|
30
|
+
Regexp.new s
|
31
|
+
end
|
32
|
+
|
33
|
+
# Do these two patterns intersect?
|
34
|
+
#--
|
35
|
+
# This might be improved by following the (much simpler, but related)
|
36
|
+
# algorithm here:
|
37
|
+
#
|
38
|
+
# http://groups.google.com/group/comp.theory/browse_frm/thread/f33e033269bd5ab0/c87e19081f45454c?lnk=st&q=regular+expression+intersection&rnum=1&hl=en#c87e19081f45454c
|
39
|
+
#
|
40
|
+
# That is, convert each regexp into an NFA, then generate the set of valid
|
41
|
+
# state pairs, then check if the pair of final states is included.
|
42
|
+
# That's basically what I'm doing here, but I'm not generating all the
|
43
|
+
# state pairs, I'm just doing a search. My way may be faster and/or
|
44
|
+
# smaller, or it may not. My initial feeling is that it is faster since
|
45
|
+
# we're basically doing a depth-first search and OSC patterns are going to
|
46
|
+
# tend to be fairly simple. Still it might be a fun experiment for the
|
47
|
+
# masochistic.
|
48
|
+
def self.intersect?(s1,s2)
|
49
|
+
r = /\*|\?|\[[^\]]*\]|\{[^\}]*\}|./
|
50
|
+
a = s1.to_s.scan r
|
51
|
+
b = s2.to_s.scan r
|
52
|
+
q = [[a,b]]
|
53
|
+
until q.empty?
|
54
|
+
q.uniq!
|
55
|
+
a,b = q.pop
|
56
|
+
a = a.dup
|
57
|
+
b = b.dup
|
58
|
+
|
59
|
+
return true if a.empty? and b.empty?
|
60
|
+
next if a.empty? or b.empty?
|
61
|
+
|
62
|
+
x,y = a.shift, b.shift
|
63
|
+
|
64
|
+
# branch {}
|
65
|
+
if x =~ /^\{/
|
66
|
+
x.scan /[^\{\},]+/ do |x|
|
67
|
+
q.push [x.scan(/./)+a,[y]+b]
|
68
|
+
end
|
69
|
+
next
|
70
|
+
end
|
71
|
+
if y =~ /^\{/
|
72
|
+
y.scan /[^\{\},]+/ do |y|
|
73
|
+
q.push [[x]+a,y.scan(/./)+b]
|
74
|
+
end
|
75
|
+
next
|
76
|
+
end
|
77
|
+
|
78
|
+
# sort
|
79
|
+
if y =~ /^\[/
|
80
|
+
x,y = y,x
|
81
|
+
a,b = b,a
|
82
|
+
end
|
83
|
+
if y =~ /^(\*|\?)/
|
84
|
+
x,y = y,x
|
85
|
+
a,b = b,a
|
86
|
+
end
|
87
|
+
|
88
|
+
# match
|
89
|
+
case x
|
90
|
+
when '*'
|
91
|
+
unless y == '/'
|
92
|
+
q.push [a,b]
|
93
|
+
q.push [[x]+a,b]
|
94
|
+
end
|
95
|
+
if y == '*'
|
96
|
+
q.push [a,[y]+b]
|
97
|
+
q.push [[x]+a,b]
|
98
|
+
end
|
99
|
+
when '?'
|
100
|
+
q.push [a,b] unless y == '/'
|
101
|
+
q.push [a,[y]+b] if y == '*'
|
102
|
+
when /^\[/
|
103
|
+
xinv = (x[1] == ?!)
|
104
|
+
yinv = (y =~ /^\[!/)
|
105
|
+
x = x[(xinv ? 2 : 1)..-2].scan(/./).to_set
|
106
|
+
if y =~ /^\[/
|
107
|
+
y = y[(yinv ? 2 : 1)..-2].scan(/./).to_set
|
108
|
+
else
|
109
|
+
y = [y].to_set
|
110
|
+
end
|
111
|
+
|
112
|
+
# simplifying assumption: nobody in their right mind is going to do
|
113
|
+
# [^everyprintablecharacter]
|
114
|
+
if xinv and yinv
|
115
|
+
q.push [a,b]
|
116
|
+
elsif xinv and not yinv
|
117
|
+
q.push [a,b] unless (y-x).empty?
|
118
|
+
elsif not xinv and yinv
|
119
|
+
q.push [a,b] unless (x-y).empty?
|
120
|
+
else
|
121
|
+
q.push [a,b] unless (x&y).empty?
|
122
|
+
end
|
123
|
+
else
|
124
|
+
q.push [a,b] if x == y
|
125
|
+
end
|
126
|
+
end
|
127
|
+
|
128
|
+
false # no intersection
|
129
|
+
end
|
130
|
+
end
|
131
|
+
end
|
data/lib/osc/server.rb
ADDED
@@ -0,0 +1,94 @@
|
|
1
|
+
module OSC
|
2
|
+
# Mixin for making servers.
|
3
|
+
# Your job is to read a packet and call dispatch(Packet.decode(raw)), ad
|
4
|
+
# infinitum (e.g. in a method named serve).
|
5
|
+
module Server
|
6
|
+
# prock.respond_to?(:call) #=> true
|
7
|
+
# Pass an OSC pattern, a typespec, and either prock or a block.
|
8
|
+
# The block/prock will be called if the pattern and typspec match. Numeric
|
9
|
+
# types will be coerced, so e.g. 'fi' would match 'ii' and the float would
|
10
|
+
# be coerced to an int.
|
11
|
+
def add_method(pat, typespec, prock=nil, &block)
|
12
|
+
pat = Pattern.new(pat) unless Pattern === pat
|
13
|
+
if block_given? and prock
|
14
|
+
raise ArgumentError, 'Specify either a block or a Proc, not both.'
|
15
|
+
end
|
16
|
+
prock = block if block_given?
|
17
|
+
unless prock.respond_to?(:call)
|
18
|
+
raise ArgumentError, "Prock doesn't respond to :call"
|
19
|
+
end
|
20
|
+
unless typespec.nil? or typespec =~ /[ifsb]*/
|
21
|
+
raise ArgumentError, "Bad typespec '#{typespec}'"
|
22
|
+
end
|
23
|
+
@cb ||= []
|
24
|
+
@cb << [pat, typespec, prock]
|
25
|
+
end
|
26
|
+
|
27
|
+
# dispatch the provided message. It can be raw or already decoded with
|
28
|
+
# Packet.decode
|
29
|
+
def dispatch(mesg)
|
30
|
+
case mesg
|
31
|
+
when Bundle, Message
|
32
|
+
else
|
33
|
+
mesg = Packet.decode(mesg)
|
34
|
+
end
|
35
|
+
|
36
|
+
case mesg
|
37
|
+
when Bundle; dispatch_bundle(mesg)
|
38
|
+
when Message
|
39
|
+
unless @cb.nil?
|
40
|
+
@cb.each do |pat, typespec, obj|
|
41
|
+
if pat.nil? or Pattern.intersect?(pat, mesg.address)
|
42
|
+
if typespec
|
43
|
+
if typespec.size == mesg.args.size
|
44
|
+
match = true
|
45
|
+
typespec.size.times do |i|
|
46
|
+
c = typespec[i]
|
47
|
+
case c
|
48
|
+
when ?i, ?f
|
49
|
+
match &&= (Numeric === mesg.args[i])
|
50
|
+
when ?s, ?b
|
51
|
+
match &&= (String === mesg.args[i])
|
52
|
+
end
|
53
|
+
end
|
54
|
+
if match
|
55
|
+
typespec.size.times do |i|
|
56
|
+
case typespec[i]
|
57
|
+
when ?i
|
58
|
+
mesg.args[i] = mesg.args[i].to_i
|
59
|
+
when ?f
|
60
|
+
mesg.args[i] = mesg.args[i].to_f
|
61
|
+
when ?s,?b
|
62
|
+
mesg.args[i] = mesg.args[i].to_s
|
63
|
+
mesg.args[i] = mesg.args[i].to_s
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
obj.call(mesg)
|
68
|
+
end
|
69
|
+
end
|
70
|
+
else # no typespec
|
71
|
+
obj.call(mesg)
|
72
|
+
end
|
73
|
+
end # pattern match
|
74
|
+
end # @cb.each
|
75
|
+
end # unless @cb.nil?
|
76
|
+
else
|
77
|
+
raise "bad mesg"
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
# May create a new thread to wait to dispatch according to p.timetag.
|
82
|
+
def dispatch_bundle(p)
|
83
|
+
diff = p.timetag.to_f - TimeTag.now.to_f
|
84
|
+
if diff <= 0
|
85
|
+
p.each {|m| m.source = p.source; dispatch m}
|
86
|
+
else
|
87
|
+
Thread.new do
|
88
|
+
sleep diff
|
89
|
+
p.each {|m| m.source = p.source; dispatch m}
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
module OSC
|
2
|
+
# Mixin for OSC transports. You implement (or in many cases just alias)
|
3
|
+
# send_raw, recvfrom_raw, and recv_raw, which have the semantics of send,
|
4
|
+
# recvfrom, and recv in e.g. UDPSocket
|
5
|
+
module Transport
|
6
|
+
# Send a Message, Bundle, or even raw data
|
7
|
+
def send(msg, *args)
|
8
|
+
case msg
|
9
|
+
when Message,Bundle
|
10
|
+
send_raw(msg.encode, *args)
|
11
|
+
else
|
12
|
+
send_raw(msg, *args)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
# Receive a Message, Bundle, or raw data and the sender. The source
|
17
|
+
# attribute of the Message or Bundle is also set to sender. e.g.
|
18
|
+
# packet, sender = udp_osc_client.recvfrom(32768)
|
19
|
+
def recvfrom(*args)
|
20
|
+
data, sender = recvfrom_raw(*args)
|
21
|
+
m = Packet.decode(data)
|
22
|
+
m.source = sender
|
23
|
+
[m, sender]
|
24
|
+
rescue
|
25
|
+
[data, sender]
|
26
|
+
end
|
27
|
+
|
28
|
+
# Receive a Message, Bundle, or raw data.
|
29
|
+
def recv(*args)
|
30
|
+
data = recv_raw(*args)
|
31
|
+
Packet.decode(data)
|
32
|
+
rescue
|
33
|
+
end
|
34
|
+
|
35
|
+
# Send a Message/Bundle with a timestamp (a Time or TimeTag object).
|
36
|
+
def send_timestamped(msg, ts, *args)
|
37
|
+
m = Bundle.new(ts, msg)
|
38
|
+
send(m, *args)
|
39
|
+
end
|
40
|
+
alias :send_ts :send_timestamped
|
41
|
+
end
|
42
|
+
end
|
data/lib/osc/udp.rb
ADDED
@@ -0,0 +1,30 @@
|
|
1
|
+
require 'osc/transport'
|
2
|
+
require 'socket'
|
3
|
+
|
4
|
+
module OSC
|
5
|
+
# A ::UDPSocket with a send method that accepts a Message or Bundle or
|
6
|
+
# a raw String.
|
7
|
+
class UDPSocket < ::UDPSocket
|
8
|
+
alias :send_raw :send
|
9
|
+
alias :recvfrom_raw :recvfrom
|
10
|
+
alias :recv_raw :recv
|
11
|
+
include Transport
|
12
|
+
end
|
13
|
+
|
14
|
+
class UDPServer < OSC::UDPSocket
|
15
|
+
MAX_MSG_SIZE=32768
|
16
|
+
include Server
|
17
|
+
def serve
|
18
|
+
loop do
|
19
|
+
p, sender = recvfrom(MAX_MSG_SIZE)
|
20
|
+
dispatch p
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
# send msg2 as a reply to msg1
|
25
|
+
def reply(msg1, msg2)
|
26
|
+
domain, port, host, ip = msg2.source
|
27
|
+
send(msg2, 0, host, port)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
data/lib/rosc.rb
ADDED
data/script/console
ADDED
@@ -0,0 +1,10 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# File: script/console
|
3
|
+
irb = RUBY_PLATFORM =~ /(:?mswin|mingw)/ ? 'irb.bat' : 'irb'
|
4
|
+
|
5
|
+
libs = " -r irb/completion"
|
6
|
+
# Perhaps use a console_lib to store any extra methods I may want available in the cosole
|
7
|
+
# libs << " -r #{File.dirname(__FILE__) + '/../lib/console_lib/console_logger.rb'}"
|
8
|
+
libs << " -r #{File.dirname(__FILE__) + '/../lib/rosc.rb'}"
|
9
|
+
puts "Loading rosc gem"
|
10
|
+
exec "#{irb} #{libs} --simple-prompt"
|
data/script/destroy
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
APP_ROOT = File.expand_path(File.join(File.dirname(__FILE__), '..'))
|
3
|
+
|
4
|
+
begin
|
5
|
+
require 'rubigen'
|
6
|
+
rescue LoadError
|
7
|
+
require 'rubygems'
|
8
|
+
require 'rubigen'
|
9
|
+
end
|
10
|
+
require 'rubigen/scripts/destroy'
|
11
|
+
|
12
|
+
ARGV.shift if ['--help', '-h'].include?(ARGV[0])
|
13
|
+
RubiGen::Base.use_component_sources! [:rubygems, :newgem, :newgem_theme, :test_unit]
|
14
|
+
RubiGen::Scripts::Destroy.new.run(ARGV)
|
data/script/generate
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
APP_ROOT = File.expand_path(File.join(File.dirname(__FILE__), '..'))
|
3
|
+
|
4
|
+
begin
|
5
|
+
require 'rubigen'
|
6
|
+
rescue LoadError
|
7
|
+
require 'rubygems'
|
8
|
+
require 'rubigen'
|
9
|
+
end
|
10
|
+
require 'rubigen/scripts/generate'
|
11
|
+
|
12
|
+
ARGV.shift if ['--help', '-h'].include?(ARGV[0])
|
13
|
+
RubiGen::Base.use_component_sources! [:rubygems, :newgem, :newgem_theme, :test_unit]
|
14
|
+
RubiGen::Scripts::Generate.new.run(ARGV)
|
data/test/test_osc.rb
ADDED
@@ -0,0 +1,160 @@
|
|
1
|
+
$:.unshift(File.dirname(__FILE__) + "/../lib/")
|
2
|
+
require 'osc'
|
3
|
+
require 'time'
|
4
|
+
require 'test/unit'
|
5
|
+
|
6
|
+
class TC_OSC < Test::Unit::TestCase
|
7
|
+
include OSC
|
8
|
+
# def setup
|
9
|
+
# end
|
10
|
+
|
11
|
+
# def teardown
|
12
|
+
# end
|
13
|
+
|
14
|
+
def test_datatype
|
15
|
+
s = 'foo'
|
16
|
+
i = 42
|
17
|
+
f = 3.14
|
18
|
+
|
19
|
+
assert_equal 'i', Packet.tag(i)
|
20
|
+
assert_equal 'f', Packet.tag(f)
|
21
|
+
assert_equal 's', Packet.tag(s)
|
22
|
+
assert_equal s+"\000", Packet.encode(s)
|
23
|
+
b = Blob.new("foobardoobar\0\0x200")
|
24
|
+
assert_equal 'b', Packet.tag(b)
|
25
|
+
assert_equal b.size+4 + (b.size+4)%4, Packet.encode(b).size
|
26
|
+
end
|
27
|
+
|
28
|
+
def test_timetag
|
29
|
+
t1 = TimeTag::JAN_1970
|
30
|
+
t2 = Time.now
|
31
|
+
t3 = t2.to_f+t1
|
32
|
+
|
33
|
+
tt = TimeTag.new t2
|
34
|
+
assert_equal t3, tt.to_f
|
35
|
+
assert_equal t3.floor, tt.to_i
|
36
|
+
assert_equal t3.floor - t3, tt.to_i - tt.to_f
|
37
|
+
assert_equal [0,1].pack('NN'), Packet.encode(TimeTag.new(nil))
|
38
|
+
assert_equal t2.to_i,tt.to_time.to_i # to_f has roundoff error at the lsb
|
39
|
+
end
|
40
|
+
|
41
|
+
def test_message
|
42
|
+
a = 'foo'
|
43
|
+
b = 'quux'
|
44
|
+
m = Message.new '/foobar', 'ssi', a, b, 1
|
45
|
+
assert_equal "/foobar\000"+",ssi\000\000\000\000"+
|
46
|
+
"foo\000"+"quux\000\000\000\000"+"\000\000\000\001", Packet.encode(m)
|
47
|
+
end
|
48
|
+
|
49
|
+
def test_bundle
|
50
|
+
m1 = Message.new '/foo','s','foo'
|
51
|
+
m2 = Message.new '/bar','s','bar'
|
52
|
+
t = Time.now
|
53
|
+
b = Bundle.new(TimeTag.new(Time.at(t + 10)), m1, m2)
|
54
|
+
b2 = Bundle.new(nil, b, m1)
|
55
|
+
|
56
|
+
assert_equal 10, b.timetag.to_time.to_i - t.to_i
|
57
|
+
e = Packet.encode(b2)
|
58
|
+
assert_equal '#bundle', e[0,7]
|
59
|
+
assert_equal "\000\000\000\000\000\000\000\001", e[8,8]
|
60
|
+
assert_equal '#bundle', e[16+4,7]
|
61
|
+
assert_equal '/foo', e[16+4+Packet.encode(b).size+4,4]
|
62
|
+
assert_equal 0, e.size % 4
|
63
|
+
|
64
|
+
assert_instance_of Array, b2.to_a
|
65
|
+
assert_instance_of Bundle, b2.to_a[0]
|
66
|
+
assert_instance_of Message, b2.to_a[1]
|
67
|
+
|
68
|
+
bundle = Packet.decode(e)
|
69
|
+
assert_instance_of Bundle, bundle
|
70
|
+
|
71
|
+
|
72
|
+
end
|
73
|
+
|
74
|
+
|
75
|
+
|
76
|
+
def test_packet
|
77
|
+
m = Message.new '/foo','s','foo'
|
78
|
+
b = Bundle.new nil,m
|
79
|
+
|
80
|
+
m2 = Packet.decode("/foo\000\000\000\000,s\000\000foo\000")
|
81
|
+
assert_equal m.address,m2.address
|
82
|
+
m2 = Packet.decode(Packet.encode(m))
|
83
|
+
assert_equal m.address,m2.address
|
84
|
+
assert_equal m.typetag,m2.typetag
|
85
|
+
assert_equal m.args.size,m2.args.size
|
86
|
+
b2 = Packet.decode(Packet.encode(b))
|
87
|
+
assert_equal b.args.size,b2.args.size
|
88
|
+
end
|
89
|
+
|
90
|
+
class TestServer
|
91
|
+
include OSC::Transport
|
92
|
+
include OSC::Server
|
93
|
+
def test_request(p)
|
94
|
+
send p
|
95
|
+
end
|
96
|
+
|
97
|
+
def send_raw(msg, *args)
|
98
|
+
dispatch msg
|
99
|
+
end
|
100
|
+
|
101
|
+
end
|
102
|
+
|
103
|
+
def test_server
|
104
|
+
s = TestServer.new
|
105
|
+
s.add_method('/foo/bar',nil) { |msg|
|
106
|
+
assert_equal 'si',msg.typetag
|
107
|
+
assert_equal 'Hello, World!',msg[0]
|
108
|
+
assert_equal 42,msg[1]
|
109
|
+
}
|
110
|
+
s.test_request Message.new("/foo/bar",'si','Hello, World!',42)
|
111
|
+
end
|
112
|
+
|
113
|
+
def test_server_with_bundle
|
114
|
+
s = TestServer.new
|
115
|
+
s.add_method('/foo/bar',nil) { |msg|
|
116
|
+
assert_equal 'si',msg.typetag
|
117
|
+
assert_equal 'Hello, World!',msg[0]
|
118
|
+
assert_equal 42,msg[1]
|
119
|
+
}
|
120
|
+
s.test_request Bundle.new(nil, Message.new("/foo/bar",'si','Hello, World!',42), Message.new("/foo/bar",'si','Hello, World!',42), Message.new("/foo/bar",'si','Hello, World!',42))
|
121
|
+
end
|
122
|
+
|
123
|
+
def test_pattern
|
124
|
+
# test *
|
125
|
+
assert Pattern.intersect?('/*/bar/baz','/foo/*/baz')
|
126
|
+
assert Pattern.intersect?('/f*','/*o')
|
127
|
+
assert ! Pattern.intersect?('/f*','/foo/bar')
|
128
|
+
assert ! Pattern.intersect?('/f*','/bar')
|
129
|
+
# test ?
|
130
|
+
assert Pattern.intersect?('/fo?/bar','/foo/?ar')
|
131
|
+
assert ! Pattern.intersect?('/foo?','/foo')
|
132
|
+
# test []
|
133
|
+
assert Pattern.intersect?('/foo/ba[rz]','/foo/bar')
|
134
|
+
assert Pattern.intersect?('/[!abcde]/a','/[!abcde]/a')
|
135
|
+
assert Pattern.intersect?('/[!abcde]/a','/f/a')
|
136
|
+
assert Pattern.intersect?('/[!abcde]/a','/[abf]/a')
|
137
|
+
assert ! Pattern.intersect?('/[ab]/a','/[!abc]/a')
|
138
|
+
assert ! Pattern.intersect?('/[abcde]','/[!abcde]')
|
139
|
+
assert ! Pattern.intersect?('/[abcde]','/f')
|
140
|
+
assert ! Pattern.intersect?('/[!abcde]','/a')
|
141
|
+
# test {}
|
142
|
+
assert Pattern.intersect?('/{foo,bar,baz}','/foo')
|
143
|
+
assert Pattern.intersect?('/{foo,bar,baz}','/bar')
|
144
|
+
assert Pattern.intersect?('/{foo,bar,baz}','/baz')
|
145
|
+
assert ! Pattern.intersect?('/{foo,bar,baz}','/quux')
|
146
|
+
assert ! Pattern.intersect?('/{foo,bar,baz}','/fo')
|
147
|
+
# * with *,?,[]
|
148
|
+
assert Pattern.intersect?('/*/bar','/*/ba?')
|
149
|
+
assert Pattern.intersect?('/*/bar','/*x/ba?')
|
150
|
+
assert Pattern.intersect?('/*/bar','/?/ba?')
|
151
|
+
assert Pattern.intersect?('/*/bar','/?x/ba?')
|
152
|
+
assert Pattern.intersect?('/*/bar','/[abcde]/ba?')
|
153
|
+
assert Pattern.intersect?('/*/bar','/[abcde]x/ba?')
|
154
|
+
assert Pattern.intersect?('/*/bar','/[!abcde]/ba?')
|
155
|
+
assert Pattern.intersect?('/*/bar','/[!abcde]x/ba?')
|
156
|
+
# ? with []
|
157
|
+
assert Pattern.intersect?('/?','/[abcde]')
|
158
|
+
assert Pattern.intersect?('/?','/[!abcde]')
|
159
|
+
end
|
160
|
+
end
|