aberant-osc-ruby 0.1.5 → 0.1.6

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,17 @@
1
+ = An OSC client for Ruby
2
+
3
+ http://opensoundcontrol.org/
4
+
5
+ == GOAL
6
+
7
+ I've used the OSC gem originally created by Tadayoshi Funaba and wanted to update it for ruby 1.9 compatibility. I'm also writing rspec tests for this library to allow others to more easily understand/update the code. It's getting closer to awesome every day...
8
+
9
+ Guaranteed to be compatible with tuio-ruby
10
+
11
+ == CREDITS
12
+
13
+ Originally created by...
14
+ Tadayoshi Funaba
15
+ http://www.funaba.org/en/
16
+
17
+ thx also to Toby Tripp and Obtiva
@@ -1,4 +1,4 @@
1
1
  ---
2
- :minor: 1
3
- :patch: 5
4
2
  :major: 0
3
+ :minor: 1
4
+ :patch: 6
@@ -4,13 +4,27 @@
4
4
  require 'forwardable'
5
5
  require 'socket'
6
6
  require 'thread'
7
+ require 'monitor'
7
8
 
9
+
10
+ $:.unshift( File.dirname( __FILE__ ) )
11
+
12
+ # core extensions
13
+ require 'osc-ruby/core_ext/object'
14
+ require 'osc-ruby/core_ext/numeric'
15
+ require 'osc-ruby/core_ext/time'
16
+
17
+
18
+ # jus the basics
8
19
  require 'osc-ruby/osc_types'
9
20
  require 'osc-ruby/packet'
21
+ require 'osc-ruby/osc_packet'
10
22
  require 'osc-ruby/message'
11
23
  require 'osc-ruby/bundle'
24
+ require 'osc-ruby/address_pattern'
12
25
 
13
- require 'osc-ruby/simple_server'
14
- require 'osc-ruby/simple_client'
26
+ # now we gettin fancy
27
+ require 'osc-ruby/server'
28
+ require 'osc-ruby/client'
15
29
 
16
30
 
@@ -0,0 +1,51 @@
1
+ module OSC
2
+ class AddressPattern
3
+ def initialize( pattern )
4
+ @pattern = pattern
5
+
6
+ generate_regex_from_pattern
7
+ end
8
+
9
+ def match?( address )
10
+ !!(@re.nil? || @re.match( address ))
11
+ end
12
+
13
+ private
14
+ def generate_regex_from_pattern
15
+ case @pattern
16
+ when NIL; @re = @pattern
17
+ when Regexp; @re = @pattern
18
+ when String
19
+
20
+ # i'm unsure what this does
21
+ # @pattern.gsub!(/[.^(|)]/, '\\1')
22
+
23
+ # handles osc single char wildcard matching
24
+ @pattern.gsub!(/\?/, '[^/]')
25
+
26
+ # handles osc * - 0 or more matching
27
+ @pattern.gsub!(/\*/, '[^/]*')
28
+
29
+ # handles [!] matching
30
+ @pattern.gsub!(/\[!/, '[^')
31
+
32
+ # handles {} matching
33
+ @pattern.gsub!(/\{/, '(')
34
+ @pattern.gsub!(/,/, '|')
35
+ @pattern.gsub!(/\}/, ')')
36
+
37
+
38
+ # keeps from matching before the begining of the pattern
39
+ @pattern.gsub!(/\A/, '\A')
40
+
41
+ # keeps from matching beyond the end,
42
+ # eg. pattern /hi does not match /hidden
43
+ @pattern.gsub!(/\z/, '\z')
44
+
45
+ @re = Regexp.new(@pattern)
46
+ else
47
+ raise ArgumentError, 'invalid pattern'
48
+ end
49
+ end
50
+ end
51
+ end
@@ -7,11 +7,11 @@ module OSC
7
7
 
8
8
  undef_method :zip
9
9
 
10
- de = (Array.instance_methods - self.instance_methods)
11
- de -= %w(assoc flatten flatten! pack rassoc transpose)
12
- de += %w(include? sort)
10
+ # de = (Array.instance_methods - self.instance_methods)
11
+ # de -= %w(assoc flatten flatten! pack rassoc transpose)
12
+ # de += %w(include? sort)
13
13
 
14
- def_delegators(:@args, *de)
14
+ # def_delegators(:@args, *de)
15
15
 
16
16
 
17
17
  def initialize(timetag=nil, *args)
@@ -1,5 +1,5 @@
1
1
  module OSC
2
- class SimpleClient
2
+ class Client
3
3
 
4
4
  def initialize(host, port)
5
5
  @so = UDPSocket.new
@@ -0,0 +1,17 @@
1
+ class Numeric
2
+ # Convert time intervals to seconds
3
+ def milliseconds; self/1000.0; end
4
+ def seconds; self; end
5
+ def minutes; self*60; end
6
+ def hours; self*60*60; end
7
+ def days; self*60*60*24; end
8
+ def weeks; self*60*60*24*7; end
9
+
10
+ # Convert seconds to other intervals
11
+ def to_milliseconds; self*1000; end
12
+ def to_seconds; self; end
13
+ def to_minutes; self/60.0; end
14
+ def to_hours; self/(60*60.0); end
15
+ def to_days; self/(60*60*24.0); end
16
+ def to_weeks; self/(60*60*24*7.0); end
17
+ end
@@ -0,0 +1,37 @@
1
+ # lifted from the ruby programming language book, thx matz!
2
+
3
+ # Obtain the Mutex associated with the object o, and then evaluate
4
+ # the block under the protection of that Mutex.
5
+ # This works like the synchronized keyword of Java.
6
+ def synchronized(o)
7
+ o.mutex.synchronize { yield }
8
+ end
9
+ # Object.mutex does not actually exist. We've got to define it.
10
+ # This method returns a unique Mutex for every object, and
11
+ # always returns the same Mutex for any particular object.
12
+ # It creates Mutexes lazily, which requires synchronization for
13
+ # thread safety.
14
+ class Object
15
+ # Return the Mutex for this object, creating it if necessary.
16
+ # The tricky part is making sure that two threads don't call
17
+ # this at the same time and end up creating two different mutexes.
18
+ def mutex
19
+ # If this object already has a mutex, just return it
20
+ return @__mutex if @__mutex
21
+
22
+ # Otherwise, we've got to create a mutex for the object.
23
+ # To do this safely we've got to synchronize on our class object.
24
+ synchronized(self.class) {
25
+ # Check again: by the time we enter this synchronized block,
26
+ # some other thread might have already created the mutex.
27
+ @__mutex = @__mutex || Mutex.new
28
+ }
29
+ # The return value is @__mutex
30
+ end
31
+ end
32
+ # The Object.mutex method defined above needs to lock the class
33
+ # if the object doesn't have a Mutex yet. If the class doesn't have
34
+ # its own Mutex yet, then the class of the class (the Class object)
35
+ # will be locked. In order to prevent infinite recursion, we must
36
+ # ensure that the Class object has a mutex.
37
+ Class.instance_eval { @__mutex = Mutex.new }
@@ -0,0 +1,6 @@
1
+ class Time
2
+
3
+ def to_ntp
4
+ self.to_f + 2208988800
5
+ end
6
+ end
@@ -1,21 +1,30 @@
1
1
  module OSC
2
2
  class Message < Packet
3
3
  extend Forwardable
4
- include Enumerable
4
+ # include Enumerable
5
5
 
6
6
  attr_accessor :address
7
- undef_method :zip
8
-
9
- de = (Array.instance_methods - self.instance_methods)
10
- de -= %w(assoc flatten flatten! pack rassoc transpose)
11
- de += %w(include? sort)
7
+ attr_accessor :time
8
+
9
+ # undef_method :zip
12
10
 
13
- def_delegators(:@args, *de)
11
+ # de = (Array.instance_methods - self.instance_methods)
12
+ # de -= %w(assoc flatten flatten! pack rassoc transpose)
13
+ # de += %w(include? sort)
14
14
 
15
+ # def_delegators(:@args, *de)
16
+
17
+ def self.new_with_time( address, time, tags=nil, *args )
18
+ message = new( address, tags, *args )
19
+ message.time = time
20
+ message
21
+ end
15
22
 
16
23
  def initialize(address, tags=nil, *args)
17
24
  @address = address
18
25
  @args = []
26
+
27
+
19
28
  args.each_with_index do |arg, i|
20
29
  if tags && tags[i]
21
30
  case tags[i]
@@ -38,14 +47,19 @@ module OSC
38
47
  end
39
48
 
40
49
 
41
- def tags() ',' + @args.collect{|x| x.tag}.join end
50
+ def tags() @args.collect{|x| x.tag}.join end
42
51
 
43
52
  def encode
44
- s = OSCString.new(@address).encode
45
- s << OSCString.new(tags).encode
53
+ s = OSCString.new( @address ).encode
54
+ s << OSCString.new( ',' + tags ).encode
46
55
  s << @args.collect{|x| x.encode}.join
47
56
  end
48
57
 
49
58
  def to_a() @args.collect{|x| x.val} end
59
+
60
+ def eql?( other )
61
+ @address == other.address &&
62
+ to_a == other.to_a
63
+ end
50
64
  end
51
65
  end
@@ -0,0 +1,42 @@
1
+ module OSC
2
+ class NetworkPacket
3
+ def initialize(str)
4
+ @str, @index = str, 0
5
+ end
6
+
7
+ def to_s
8
+ @str
9
+ end
10
+
11
+ def rem()
12
+ @str.length - @index
13
+ end
14
+
15
+ def eof? ()
16
+ rem <= 0
17
+ end
18
+
19
+ def skip(n)
20
+ @index += n
21
+ end
22
+
23
+ def skip_padding()
24
+ skip((4 - (@index % 4)) % 4)
25
+ end
26
+
27
+ def getn(n)
28
+ raise EOFError if rem < n
29
+ s = @str[@index, n]
30
+ skip(n)
31
+ s
32
+ end
33
+
34
+ def getc
35
+ raise EOFError if rem < 1
36
+ c = @str[@index]
37
+ skip(1)
38
+ c
39
+ end
40
+
41
+ end
42
+ end
@@ -9,11 +9,10 @@ module OSC
9
9
  def to_f() @val.to_f end
10
10
  def to_s() @val.to_s end
11
11
 
12
+
13
+ private
12
14
  def padding(s)
13
15
  s + ("\000" * ((4 - (s.size % 4)) % 4))
14
16
  end
15
-
16
- private :padding
17
-
18
17
  end
19
18
  end
@@ -0,0 +1,113 @@
1
+ require File.join( File.dirname( __FILE__ ), 'network_packet')
2
+ require 'ostruct'
3
+
4
+ module OSC
5
+ class OSCPacket
6
+ def self.messages_from_network( string )
7
+ messages = []
8
+ osc = new( string )
9
+
10
+ if osc.bundle?
11
+ bundle = osc.get_string
12
+ time = osc.get_timestamp
13
+
14
+ osc.get_bundle_messages.each do | message |
15
+ messages << decode_simple_message( time, OSCPacket.new( message ) )
16
+ end
17
+
18
+ else
19
+ messages << decode_simple_message( time, osc )
20
+ end
21
+
22
+ return messages
23
+ end
24
+
25
+ def self.decode_simple_message( time, osc_packet )
26
+ address = osc_packet.get_string
27
+ args = osc_packet.get_arguments
28
+
29
+ Message.new_with_time(address, time, nil, *args )
30
+ end
31
+
32
+ def initialize( string )
33
+ @packet = NetworkPacket.new( string )
34
+
35
+ @types = { "i" => lambda{ OSCInt32.new( get_int32 ) },
36
+ "f" => lambda{ OSCFloat32.new( get_float32 ) },
37
+ "s" => lambda{ OSCString.new( get_string ) },
38
+ "b" => lambda{ OSCBlob.new( get_blob )}
39
+ }
40
+ end
41
+
42
+ def get_bundle_messages
43
+ bundle_messages = []
44
+
45
+ until @packet.eof?
46
+ l = @packet.getn(4).unpack('N')[0]
47
+ bundle_messages << @packet.getn(l)
48
+ end
49
+ bundle_messages
50
+ end
51
+
52
+ def get_string
53
+ result = ''
54
+ until (c = @packet.getc) == 0
55
+ result << c
56
+ end
57
+
58
+ @packet.skip_padding
59
+ result
60
+ end
61
+
62
+ def get_timestamp
63
+ t1 = @packet.getn(4).unpack('N')[0]
64
+ t2 = @packet.getn(4).unpack('N')[0]
65
+ @packet.skip_padding
66
+
67
+ if t1 == 0 && t2 == 1
68
+ time = nil
69
+ else
70
+ time = t1 + t2.to_f / (2**32)
71
+ end
72
+
73
+ time
74
+ end
75
+
76
+ def get_arguments
77
+ if @packet.getc == ?,
78
+
79
+ tags = get_string
80
+ args = []
81
+
82
+ tags.scan(/./) do | tag |
83
+ args << @types[tag].call
84
+ end
85
+ args
86
+ end
87
+ end
88
+
89
+ def get_int32
90
+ i = @packet.getn(4).unpack('N')[0]
91
+ i -= 2**32 if i > (2**31-1)
92
+ @packet.skip_padding
93
+ i
94
+ end
95
+
96
+ def get_float32
97
+ f = @packet.getn(4).unpack('g')[0]
98
+ @packet.skip_padding
99
+ f
100
+ end
101
+
102
+ def get_blob
103
+ l = @packet.getn(4).unpack('N')[0]
104
+ b = @packet.getn(l)
105
+ @packet.skip_padding
106
+ b
107
+ end
108
+
109
+ def bundle?
110
+ !(@packet.to_s =~ /\A\#bundle/).nil?
111
+ end
112
+ end
113
+ end
@@ -11,7 +11,7 @@ require 'osc-ruby/osc_argument'
11
11
  class OSCFloat32 < OSCArgument
12
12
 
13
13
  def tag() 'f' end
14
- def encode() [@val].pack('g') end # fake
14
+ def encode() [@val].pack('g') end # fake - why fake?
15
15
 
16
16
  end
17
17
 
@@ -2,11 +2,25 @@ module OSC
2
2
  class Packet
3
3
 
4
4
  class PO
5
- def initialize(str) @str, @index = str, 0 end
6
- def rem() @str.length - @index end
7
- def eof? () rem <= 0 end
8
- def skip(n) @index += n end
9
- def skip_padding() skip((4 - (@index % 4)) % 4) end
5
+ def initialize(str)
6
+ @str, @index = str, 0
7
+ end
8
+
9
+ def rem()
10
+ @str.length - @index
11
+ end
12
+
13
+ def eof? ()
14
+ rem <= 0
15
+ end
16
+
17
+ def skip(n)
18
+ @index += n
19
+ end
20
+
21
+ def skip_padding()
22
+ skip((4 - (@index % 4)) % 4)
23
+ end
10
24
 
11
25
  def getn(n)
12
26
  raise EOFError if rem < n
@@ -0,0 +1,88 @@
1
+ module OSC
2
+ class Server
3
+
4
+ def initialize(port)
5
+ @socket = UDPSocket.new
6
+ @socket.bind('', port)
7
+ @cb = []
8
+ @queue = Queue.new
9
+ end
10
+
11
+ def run
12
+ start_dispatcher
13
+
14
+ start_detector
15
+ end
16
+
17
+ def stop
18
+ @socket.close
19
+ end
20
+
21
+ def add_method(address_pattern, &proc)
22
+ matcher = AddressPattern.new( address_pattern )
23
+
24
+ @cb << [matcher, proc]
25
+ end
26
+
27
+ private
28
+
29
+ def start_detector
30
+ begin
31
+ detector
32
+ rescue
33
+ Thread.main.raise $!
34
+ end
35
+ end
36
+
37
+ def start_dispatcher
38
+ Thread.fork do
39
+ begin
40
+ dispatcher
41
+ rescue
42
+ Thread.main.raise $!
43
+ end
44
+ end
45
+ end
46
+
47
+ def sendmesg(mesg)
48
+ @cb.each do |matcher, obj|
49
+ if matcher.match?( mesg.address )
50
+ obj.call( mesg )
51
+ end
52
+ end
53
+ end
54
+
55
+ def dispatcher
56
+ loop do
57
+ mesg = @queue.pop
58
+
59
+ dispatch_message( mesg )
60
+ end
61
+ end
62
+
63
+ def detector
64
+ loop do
65
+ pa = @socket.recv(16384)
66
+ begin
67
+ OSCPacket.messages_from_network(pa).each{|x| @queue.push(x)}
68
+ rescue EOFError
69
+ end
70
+ end
71
+ end
72
+
73
+ def dispatch_message( message )
74
+ diff = ( message.time || 0 ) - Time.now.to_ntp
75
+
76
+ if diff <= 0
77
+ sendmesg( message)
78
+ else # spawn a thread to wait until it's time
79
+ Thread.fork do
80
+ sleep(diff)
81
+ sendmesg(mesg)
82
+ Thread.exit
83
+ end
84
+ end
85
+ end
86
+
87
+ end
88
+ end
@@ -0,0 +1,51 @@
1
+ class MessageBuilder
2
+
3
+ def initialize
4
+ @address = ""
5
+ @tags = []
6
+ @values = []
7
+ @time = nil
8
+ end
9
+
10
+ def with_address( addr )
11
+ @address = addr
12
+ self
13
+ end
14
+
15
+ def with_float( float )
16
+ with_arg( "f", float )
17
+ self
18
+ end
19
+
20
+ def with_int( int )
21
+ with_arg( "i", int )
22
+ self
23
+ end
24
+
25
+ def with_string( string )
26
+ with_arg( "s", string )
27
+ self
28
+ end
29
+
30
+ def with_blob( blob )
31
+ with_arg( "b", blob )
32
+ self
33
+ end
34
+
35
+ def with_time( time )
36
+ @time = time
37
+ end
38
+
39
+ def build
40
+ message = OSC::Message.new( @address , @tags.join, *@values)
41
+ message.time = @time
42
+ message
43
+ end
44
+
45
+ private
46
+
47
+ def with_arg( tag, value )
48
+ @tags << tag
49
+ @values << value
50
+ end
51
+ end
@@ -3,8 +3,10 @@ require 'spec'
3
3
  require 'rr'
4
4
 
5
5
  $:.unshift( File.join( File.dirname( __FILE__), '..', 'lib' ) )
6
+ $:.unshift( File.dirname( __FILE__ ) )
6
7
 
7
8
  require 'osc-ruby'
9
+ require 'builders/message_builder'
8
10
 
9
11
  Spec::Runner.configure do |config|
10
12
  config.mock_with RR::Adapters::Rspec
@@ -0,0 +1,83 @@
1
+ require File.join( File.dirname(__FILE__) , '..', 'spec_helper' )
2
+
3
+ describe OSC::AddressPattern do
4
+ it "should match anything if the pattern is nil" do
5
+ ap = OSC::AddressPattern.new( nil )
6
+
7
+ ap.match?( "/some/nonsense").should be_true
8
+ ap.match?( "/completely.different").should be_true
9
+ end
10
+
11
+ it "should match based on a regex" do
12
+ ap = OSC::AddressPattern.new( /hi/ )
13
+
14
+ ap.match?( '/hi' ).should be_true
15
+ ap.match?( '/hidden' ).should be_true
16
+
17
+ ap.match?( '/bye' ).should be_false
18
+ end
19
+
20
+ it "should return a regex if the pattern is a string" do
21
+ ap = OSC::AddressPattern.new( "/hi" )
22
+
23
+ ap.match?('/hi').should be_true
24
+
25
+ ap.match?(' /hi').should be_false
26
+ ap.match?('/ahi').should be_false
27
+ ap.match?( '/hidden' ).should be_false
28
+ ap.match?( '/bye' ).should be_false
29
+ end
30
+
31
+ it "should match with question mark" do
32
+ ap = OSC::AddressPattern.new( "/h?l" )
33
+
34
+ ap.match?('/hal').should be_true
35
+ ap.match?('/hel').should be_true
36
+ ap.match?('/hil').should be_true
37
+ ap.match?('/hol').should be_true
38
+ ap.match?('/hul').should be_true
39
+ ap.match?('/hub').should be_false
40
+ end
41
+
42
+ it "should match with *" do
43
+ ap = OSC::AddressPattern.new( "/believ*d" )
44
+
45
+ ap.match?('/believd').should be_true
46
+ ap.match?('/believed').should be_true
47
+ ap.match?('/believeeed').should be_true
48
+ ap.match?('/believaeeeioud').should be_true
49
+ ap.match?('/believaeeeioud').should be_true
50
+ end
51
+
52
+ it "should match with []" do
53
+ ap = OSC::AddressPattern.new( "/believ[aeiou]d" )
54
+
55
+ ap.match?('/believad').should be_true
56
+ ap.match?('/believed').should be_true
57
+ ap.match?('/believid').should be_true
58
+ ap.match?('/believod').should be_true
59
+ ap.match?('/believud').should be_true
60
+ ap.match?('/believkd').should be_false
61
+ end
62
+
63
+ it "should match with [!]" do
64
+ ap = OSC::AddressPattern.new( "/believ[!aeiou]d" )
65
+
66
+ ap.match?('/believad').should be_false
67
+ ap.match?('/believed').should be_false
68
+ ap.match?('/believid').should be_false
69
+ ap.match?('/believod').should be_false
70
+ ap.match?('/believud').should be_false
71
+ ap.match?('/believkd').should be_true
72
+ ap.match?('/believzd').should be_true
73
+ end
74
+
75
+ it "should match with {}" do
76
+ ap = OSC::AddressPattern.new( "/{hi,bye}" )
77
+
78
+ ap.match?('/hi').should be_true
79
+ ap.match?('/bye').should be_true
80
+ ap.match?('/greetings').should be_false
81
+ end
82
+
83
+ end
@@ -0,0 +1,6 @@
1
+ require File.join( File.dirname(__FILE__) , '..', 'spec_helper' )
2
+
3
+
4
+ describe OSC::Bundle do
5
+
6
+ end
@@ -0,0 +1,34 @@
1
+ # some test data for when i unit test this
2
+ # @simple_packet = "/hi\000,\000\000\000"
3
+ # @simple_with_integer_arg = "/hi\000,i\000\000\000\000\000*"
4
+ # @simple_with_two_integer_args = "/hi\000,ii\000\000\000\000*\000\000\000!"
5
+ # @simple_with_float_arg = "/hi\000,f\000\000B(\n="
6
+ # @simple_with_two_float_args = "/hi\000,ff\000B(\n=B\004\n="
7
+ # @simple_with_string_arg = "/hi\000,s\000\000greetings\000\000\000"
8
+ # @simple_with_two_string_args = "/hi\000,ss\000greetings\000\000\000how are you?\000\000\000\000"
9
+ # @simple_with_int_float_string = "/hi\000,ifs\000\000\000\000\000\000\000*B\004\n=greetings\000\000\000"
10
+
11
+ require File.join( File.dirname(__FILE__) , '..', 'spec_helper' )
12
+
13
+
14
+ describe OSC::Message do
15
+ before :each do
16
+ @builder = MessageBuilder.new
17
+ @builder.with_int( 42 ).
18
+ with_int( 33 )
19
+
20
+ @message = @builder.build
21
+ end
22
+
23
+ it "should have no arguments if you define none" do
24
+ m = OSC::Message.new( "/hi" )
25
+ m.to_a.should == []
26
+ end
27
+
28
+ it "should have accept int arguments" do
29
+ m = OSC::Message.new( "/hi", "i", 42 )
30
+ m.to_a.should == [42]
31
+ m.tags.should == "i"
32
+ end
33
+
34
+ end
@@ -0,0 +1,33 @@
1
+ require File.join( File.dirname(__FILE__) , '..', 'spec_helper' )
2
+
3
+
4
+ describe OSC::NetworkPacket do
5
+ before :each do
6
+ @empty = OSC::NetworkPacket.new( "" )
7
+ @simple = OSC::NetworkPacket.new( "abc" )
8
+ end
9
+
10
+ it "should know if it's at the end of the stream" do
11
+ @empty.eof?.should be_true
12
+ end
13
+
14
+ it "should know the remainder in the stream" do
15
+ @simple.rem.should == 3
16
+ end
17
+
18
+ it "should be able to skip positions" do
19
+ @simple.skip( 1 )
20
+ @simple.rem.should == 2
21
+ end
22
+
23
+ it "should be able to get a character from the stream" do
24
+ @simple.getc.should == ?a
25
+ @simple.getc.should == ?b
26
+ @simple.getc.should == ?c
27
+ @simple.eof?.should be_true
28
+ end
29
+
30
+ it "should be able to get a number of characters from the stream" do
31
+ @simple.getn(3).should == "abc"
32
+ end
33
+ end
@@ -0,0 +1,39 @@
1
+ require File.join( File.dirname(__FILE__) , '..', 'spec_helper' )
2
+
3
+
4
+ describe OSC::OSCPacket do
5
+ before :each do
6
+ @complex_packet = "#bundle\000\316\034\315T\000\003\030\370\000\000\000$/tuio/2Dobj\000,ss\000source\000\000simulator\000\000\000\000\000\000\030/tuio/2Dobj\000,s\000\000alive\000\000\000\000\000\000\034/tuio/2Dobj\000,si\000fseq\000\000\000\000\377\377\377\377"
7
+
8
+ @messages = OSC::OSCPacket.messages_from_network( @complex_packet )
9
+ end
10
+
11
+ it "should have three messages" do
12
+ @messages.should have(3).items
13
+ end
14
+
15
+ it "should have the propper address for the messages" do
16
+ 3.times do |i|
17
+ @messages[i].address.should eql("/tuio/2Dobj")
18
+ end
19
+ end
20
+
21
+ it "should have a first message with two strings" do
22
+ args = @messages[0].to_a
23
+
24
+ args[0].should eql( "source" )
25
+ args[1].should eql( "simulator" )
26
+ end
27
+
28
+ it "should have a second message with one string" do
29
+ args = @messages[1].to_a
30
+ args[0].should eql( "alive" )
31
+ end
32
+
33
+ it "should have a third message with a string and an int" do
34
+ args = @messages[2].to_a
35
+
36
+ args[0].should eql( "fseq" )
37
+ args[1].should eql(-1)
38
+ end
39
+ end
@@ -0,0 +1,108 @@
1
+ require File.join( File.dirname(__FILE__) , '..', 'spec_helper' )
2
+
3
+
4
+ describe OSC::OSCPacket do
5
+ before :each do
6
+ @address = "/hi"
7
+ @first_int = 42
8
+ @second_int = 33
9
+
10
+ @first_float = 42.01
11
+ @second_float = 33.01
12
+
13
+ @first_string = "greetings"
14
+ @second_string = "how are you?"
15
+
16
+ @first_blob = "this is a fake blob"
17
+ @second_blob = "tis another fake blob"
18
+
19
+ @builder = MessageBuilder.new
20
+ @builder.with_address( @address )
21
+ end
22
+
23
+ it "should decode the address of a simple message from the network data" do
24
+ sent_msg = @builder.build
25
+
26
+ msg = OSC::OSCPacket.messages_from_network( sent_msg.encode )
27
+
28
+ msg.first.address.should == @address
29
+ end
30
+
31
+ it "should decode the int arg of a simple message from the network data" do
32
+ sent_msg = @builder.with_int( @first_int ).build
33
+
34
+ msg = OSC::OSCPacket.messages_from_network( sent_msg.encode )
35
+
36
+ msg.first.to_a.should == [@first_int]
37
+ end
38
+
39
+ it "should decode two int args" do
40
+ sent_msg = @builder.with_int( @first_int ).with_int( @second_int ).build
41
+
42
+ msg = OSC::OSCPacket.messages_from_network( sent_msg.encode )
43
+
44
+ msg.first.to_a.should == [@first_int, @second_int]
45
+ end
46
+
47
+ it "shold decode address with float arg" do
48
+ sent_msg = @builder.with_float( @first_float ).build
49
+
50
+ msg = OSC::OSCPacket.messages_from_network( sent_msg.encode )
51
+
52
+ msg.first.to_a[0].should be_close( @first_float, 0.001 )
53
+ end
54
+
55
+
56
+ it "shold decode address with two float args" do
57
+ sent_msg = @builder.with_float( @first_float ).with_float( @second_float).build
58
+
59
+ msg = OSC::OSCPacket.messages_from_network( sent_msg.encode )
60
+
61
+ args = msg.first.to_a
62
+ args.first.should be_close( @first_float, 0.001 )
63
+ args[1].should be_close( @second_float, 0.0001 )
64
+ end
65
+
66
+ it "should decode address with string arg" do
67
+ sent_msg = @builder.with_string( @first_string ).build
68
+
69
+ msg = OSC::OSCPacket.messages_from_network( sent_msg.encode )
70
+
71
+ msg.first.to_a.should == [@first_string]
72
+ end
73
+
74
+ it "should decode address with multiple string args" do
75
+ sent_msg = @builder.with_string( @first_string ).with_string( @second_string).build
76
+ msg = OSC::OSCPacket.messages_from_network( sent_msg.encode )
77
+
78
+ args = msg.first.to_a
79
+ args[0].should == @first_string
80
+ args[1].should == @second_string
81
+ end
82
+
83
+
84
+ it "should decode messages with three different types of args" do
85
+ sent_msg = @builder.with_int( @first_int ).
86
+ with_float( @second_float ).
87
+ with_string( @first_string ).
88
+ build
89
+
90
+ msg = OSC::OSCPacket.messages_from_network( sent_msg.encode )
91
+
92
+ args = msg.first.to_a
93
+
94
+ args[0].should eql( @first_int )
95
+ args[1].should be_close( @second_float, 0.0001 )
96
+ args[2].should eql( @first_string )
97
+ end
98
+
99
+ it "should decode messages with blobs" do
100
+ sent_msg = @builder.with_blob( @first_blob ).build
101
+
102
+
103
+ msg = OSC::OSCPacket.messages_from_network( sent_msg.encode )
104
+
105
+ args = msg.first.to_a
106
+ args.first.should eql( @first_blob )
107
+ end
108
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: aberant-osc-ruby
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.5
4
+ version: 0.1.6
5
5
  platform: ruby
6
6
  authors:
7
7
  - aberant
@@ -9,7 +9,7 @@ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
 
12
- date: 2009-07-16 00:00:00 -07:00
12
+ date: 2009-08-29 00:00:00 -07:00
13
13
  default_executable:
14
14
  dependencies: []
15
15
 
@@ -20,28 +20,41 @@ executables: []
20
20
  extensions: []
21
21
 
22
22
  extra_rdoc_files:
23
- - README
23
+ - README.rdoc
24
24
  files:
25
+ - README.rdoc
25
26
  - VERSION.yml
26
27
  - lib/osc-ruby
28
+ - lib/osc-ruby/address_pattern.rb
27
29
  - lib/osc-ruby/bundle.rb
30
+ - lib/osc-ruby/client.rb
31
+ - lib/osc-ruby/core_ext
32
+ - lib/osc-ruby/core_ext/numeric.rb
33
+ - lib/osc-ruby/core_ext/object.rb
34
+ - lib/osc-ruby/core_ext/time.rb
28
35
  - lib/osc-ruby/message.rb
36
+ - lib/osc-ruby/network_packet.rb
29
37
  - lib/osc-ruby/osc_argument.rb
38
+ - lib/osc-ruby/osc_packet.rb
30
39
  - lib/osc-ruby/osc_types.rb
31
40
  - lib/osc-ruby/packet.rb
32
- - lib/osc-ruby/simple_client.rb
33
- - lib/osc-ruby/simple_server.rb
41
+ - lib/osc-ruby/server.rb
34
42
  - lib/osc-ruby.rb
35
- - spec/integration
36
- - spec/integration/send_receive_spec.rb
43
+ - spec/builders
44
+ - spec/builders/message_builder.rb
37
45
  - spec/spec_helper.rb
38
46
  - spec/unit
47
+ - spec/unit/address_pattern_spec.rb
48
+ - spec/unit/message_bundle_spec.rb
49
+ - spec/unit/message_spec.rb
50
+ - spec/unit/network_packet_spec.rb
39
51
  - spec/unit/osc_argument_spec.rb
52
+ - spec/unit/osc_complex_packets_spec.rb
53
+ - spec/unit/osc_simple_packets_spec.rb
40
54
  - spec/unit/osc_types_spec.rb
41
- - spec/unit/simple_client_spec.rb
42
- - README
43
55
  has_rdoc: true
44
56
  homepage: http://github.com/aberant/osc-ruby
57
+ licenses:
45
58
  post_install_message:
46
59
  rdoc_options:
47
60
  - --inline-source
@@ -63,7 +76,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
63
76
  requirements: []
64
77
 
65
78
  rubyforge_project:
66
- rubygems_version: 1.2.0
79
+ rubygems_version: 1.3.5
67
80
  signing_key:
68
81
  specification_version: 2
69
82
  summary: inital gem
data/README DELETED
@@ -1,14 +0,0 @@
1
- An "OSC" module
2
- ==============
3
-
4
- OSC is an "OpenSound Control" module for an object‐oriented
5
- scripting language Ruby.
6
-
7
-
8
-
9
-
10
-
11
- Originally created by...
12
- Tadayoshi Funaba
13
- mailto:tadf@funaba.org
14
- http://www.funaba.org/en/
@@ -1,93 +0,0 @@
1
- module OSC
2
- class SimpleServer
3
-
4
- def initialize(port)
5
- @so = UDPSocket.new
6
- @so.bind('', port)
7
- @cb = []
8
- @qu = Queue.new
9
- end
10
-
11
- def add_method(pat, obj=nil, &proc)
12
- case pat
13
- when NIL; re = pat
14
- when Regexp; re = pat
15
- when String
16
- pat = pat.dup
17
- pat.gsub!(/[.^(|)]/, '\\1')
18
- pat.gsub!(/\?/, '[^/]')
19
- pat.gsub!(/\*/, '[^/]*')
20
- pat.gsub!(/\[!/, '[^')
21
- pat.gsub!(/\{/, '(')
22
- pat.gsub!(/,/, '|')
23
- pat.gsub!(/\}/, ')')
24
- pat.gsub!(/\A/, '\A')
25
- pat.gsub!(/\z/, '\z')
26
- re = Regexp.new(pat)
27
- else
28
- raise ArgumentError, 'invalid pattern'
29
- end
30
-
31
- unless ( obj && !proc) ||
32
- (!obj && proc)
33
- raise ArgumentError, 'wrong number of arguments'
34
- end
35
- @cb << [re, (obj || proc)]
36
- end
37
-
38
- def sendmesg(mesg)
39
- @cb.each do |re, obj|
40
- if re.nil? || re =~ mesg.address
41
- obj.send(if Proc === obj then :call else :accept end, mesg)
42
- end
43
- end
44
- end
45
-
46
- def dispatcher
47
- loop do
48
- time, mesg = @qu.pop
49
- now = Time.now.to_f + 2208988800
50
- diff = if time.nil?
51
- then 0 else time - now end
52
-
53
- if diff <= 0
54
- sendmesg(mesg)
55
- else
56
- Thread.fork do
57
- sleep(diff)
58
- sendmesg(mesg)
59
- Thread.exit
60
- end
61
- end
62
- end
63
- end
64
-
65
- def detector
66
- loop do
67
- pa = @so.recv(16384)
68
- begin
69
- Packet.decode(pa).each{|x| @qu.push(x)}
70
- rescue EOFError
71
- end
72
- end
73
- end
74
-
75
- private :sendmesg, :dispatcher, :detector
76
-
77
- def run
78
- Thread.fork do
79
- begin
80
- dispatcher
81
- rescue
82
- Thread.main.raise $!
83
- end
84
- end
85
-
86
- begin
87
- detector
88
- rescue
89
- Thread.main.raise $!
90
- end
91
- end
92
- end
93
- end
@@ -1,25 +0,0 @@
1
- # require File.join( File.dirname(__FILE__) , '..', 'spec_helper' )
2
- # TODO: figure out what thread magic i need to get this to work
3
-
4
- # describe "send and receive" do
5
- # it "should be able to send and receive messages" do
6
- # server = OSC::SimpleServer.new( 3333 )
7
- #
8
- # watcher = Object.new
9
- # stub( watcher ).called
10
- #
11
- # server.add_method( "/hi") do |m|
12
- # watcher.called
13
- # end
14
- #
15
- # Thread.new do
16
- # server.run
17
- # end
18
- #
19
- #
20
- # client = OSC::SimpleClient.new( "localhost", 3333 )
21
- # client.send( OSC::Message.new( "/hi" ) )
22
- #
23
- # watcher.should have_received.called
24
- # end
25
- # end
@@ -1,11 +0,0 @@
1
- require File.join( File.dirname(__FILE__) , '..', 'spec_helper' )
2
-
3
- describe OSC::SimpleClient do
4
- it "should not blow up" do
5
- udp = Object.new
6
- stub( udp ).connect
7
- stub( UDPSocket ).new.returns( udp )
8
-
9
- OSC::SimpleClient.new( "localhost", 3333 )
10
- end
11
- end