osc-ruby 0.2.0 → 0.6.0

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.
@@ -10,7 +10,7 @@ Compatible with ruby 1.8, 1.9, and jruby
10
10
 
11
11
  == Install
12
12
 
13
- sudo gem install aberant-osc-ruby
13
+ sudo gem install osc-ruby
14
14
 
15
15
  for the EMServer, you will need EventMachine
16
16
 
data/Rakefile CHANGED
@@ -1,6 +1,5 @@
1
1
  require 'spec/rake/spectask'
2
2
 
3
-
4
3
  task :default => :spec
5
4
 
6
5
  Spec::Rake::SpecTask.new do |t|
@@ -9,10 +8,26 @@ Spec::Rake::SpecTask.new do |t|
9
8
  t.spec_opts = ["--colour"]
10
9
  end
11
10
 
11
+ require 'rake/rdoctask'
12
+ Rake::RDocTask.new do |rdoc|
13
+ if File.exist?('VERSION')
14
+ version = File.read('VERSION')
15
+ else
16
+ version = ""
17
+ end
18
+
19
+ rdoc.rdoc_dir = 'rdoc'
20
+ rdoc.title = "osc-ruby #{version}"
21
+ rdoc.rdoc_files.include('README*')
22
+ rdoc.rdoc_files.include('lib/**/*.rb')
23
+ end
24
+
25
+
12
26
  begin
13
27
  require 'jeweler'
14
28
  Jeweler::Tasks.new do |gem|
15
29
  gem.name = "osc-ruby"
30
+ gem.description = "a ruby client for the OSC protocol"
16
31
  gem.summary = %Q{inital gem}
17
32
  gem.email = "qzzzq1@gmail.com"
18
33
  gem.homepage = "http://github.com/aberant/osc-ruby"
@@ -20,12 +35,10 @@ begin
20
35
  gem.files = FileList['Rakefile', 'examples/**/*', 'lib/**/*'].to_a
21
36
  gem.test_files = FileList['spec/**/*.rb']
22
37
  gem.rubyforge_project = "osc-ruby"
23
- # gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings
24
- end
25
-
26
- Jeweler::RubyforgeTasks.new do |rubyforge|
27
- rubyforge.doc_task = "rdoc"
28
38
  end
39
+
40
+ Jeweler::GemcutterTasks.new
41
+
29
42
  rescue LoadError
30
43
  puts "Jeweler not available. Install it with: sudo gem install technicalpickles-jeweler -s http://gems.github.com"
31
44
  end
@@ -1,14 +1,12 @@
1
- require File.join( File.dirname( __FILE__ ), "packet" )
2
-
3
1
  module OSC
4
- class Bundle < Packet
2
+ class Bundle
5
3
  attr_accessor :timetag
6
-
4
+
7
5
  def initialize(timetag=nil, *args)
8
6
  @timetag = timetag
9
7
  @args = args
10
8
  end
11
-
9
+
12
10
  def encode()
13
11
  s = OSCString.new('#bundle').encode
14
12
  s << encode_timetag(@timetag)
@@ -17,12 +15,9 @@ module OSC
17
15
  end.join
18
16
  end
19
17
 
20
-
21
18
  def to_a() @args.collect{|x| x.to_a} end
22
19
 
23
-
24
-
25
- private
20
+ private
26
21
 
27
22
  def encode_timetag(t)
28
23
  case t
@@ -30,16 +25,20 @@ module OSC
30
25
  t1 = 0
31
26
  t2 = 1
32
27
  when Numeric
33
- t1, fr = t.divmod(1)
34
- t2 = (fr * (2**32)).to_i
28
+ t1, t2 = construct_timetag( t )
35
29
  when Time
36
- t1, fr = (t.to_f + 2208988800).divmod(1)
37
- t2 = (fr * (2**32)).to_i
30
+ t1, t2 = construct_timetag( t.to_ntp )
38
31
  else
39
32
  raise ArgumentError, 'invalid time'
40
33
  end
41
34
  [t1, t2].pack('N2')
42
35
  end
43
36
 
37
+ def construct_timetag( time )
38
+ t1, fr = time.divmod(1)
39
+ t2 = (fr * (2**32)).to_i
40
+
41
+ [t1, t2]
42
+ end
44
43
  end
45
44
  end
@@ -9,6 +9,5 @@ module OSC
9
9
  def send(mesg)
10
10
  @so.send(mesg.encode, 0)
11
11
  end
12
-
13
12
  end
14
13
  end
@@ -2,54 +2,51 @@ require 'rubygems'
2
2
  require 'eventmachine'
3
3
  require File.join( File.dirname( __FILE__), '..', 'osc-ruby')
4
4
 
5
-
6
5
  module OSC
7
6
  Channel = EM::Channel.new
8
-
9
- class Connection < EventMachine::Connection
10
7
 
11
- def receive_data data
8
+ class Connection < EventMachine::Connection
9
+ def receive_data data
12
10
  Channel << OSC::OSCPacket.messages_from_network( data )
13
11
  end
14
12
  end
15
13
 
16
-
17
14
  class EMServer
18
-
15
+
19
16
  def initialize( port = 3333 )
20
17
  @port = port
21
18
  setup_dispatcher
22
19
  @tuples = []
23
20
  end
24
-
21
+
25
22
  def run
26
23
  EM::run { EM::open_datagram_socket "localhost", @port, Connection }
27
24
  end
28
-
25
+
29
26
  def add_method(address_pattern, &proc)
30
27
  matcher = AddressPattern.new( address_pattern )
31
-
28
+
32
29
  @tuples << [matcher, proc]
33
- end
34
-
30
+ end
31
+
35
32
  private
36
33
  def setup_dispatcher
37
34
  Channel.subscribe do |messages|
38
- messages.each do |message|
39
- diff = ( message.time || 0 ) - Time.now.to_ntp
35
+ messages.each do |message|
36
+ diff = ( message.time || 0 ) - Time.now.to_ntp
40
37
 
41
- if diff <= 0
38
+ if diff <= 0
42
39
  sendmesg( message )
43
- else
44
- EM.defer do
45
- sleep( diff )
40
+ else
41
+ EM.defer do
42
+ sleep( diff )
46
43
  sendmesg( message )
47
- end
48
- end
49
- end
44
+ end
45
+ end
46
+ end
50
47
  end
51
48
  end
52
-
49
+
53
50
  def sendmesg(mesg)
54
51
  @tuples.each do |matcher, obj|
55
52
  if matcher.match?( mesg.address )
@@ -57,7 +54,6 @@ module OSC
57
54
  end
58
55
  end
59
56
  end
60
-
61
57
  end
62
58
  end
63
59
 
@@ -1,22 +1,19 @@
1
- require File.join( File.dirname( __FILE__ ), "packet" )
2
-
3
1
  module OSC
4
- class Message < Packet
2
+ class Message
5
3
  attr_accessor :address
6
- attr_accessor :time
4
+ attr_accessor :time
7
5
 
8
-
9
6
  def self.new_with_time( address, time, tags=nil, *args )
10
7
  message = new( address, tags, *args )
11
8
  message.time = time
12
9
  message
13
10
  end
14
-
15
- def initialize(address, *args)
11
+
12
+ def initialize( address, *args )
16
13
  @address = address
17
14
  @args = []
18
-
19
- args.each_with_index do |arg, i|
15
+
16
+ args.each do |arg|
20
17
  case arg
21
18
  when Integer; @args << OSCInt32.new(arg)
22
19
  when Float; @args << OSCFloat32.new(arg)
@@ -26,7 +23,6 @@ module OSC
26
23
  end
27
24
  end
28
25
 
29
-
30
26
  def tags() @args.collect{|x| x.tag}.join end
31
27
 
32
28
  def encode
@@ -36,8 +32,8 @@ module OSC
36
32
  end
37
33
 
38
34
  def to_a() @args.collect{|x| x.val} end
39
-
40
- def eql?( other )
35
+
36
+ def ==( other )
41
37
  @address == other.address &&
42
38
  to_a == other.to_a
43
39
  end
@@ -1,29 +1,29 @@
1
1
  module OSC
2
2
  class NetworkPacket
3
- def initialize(str)
4
- @str, @index = str, 0
3
+ def initialize(str)
4
+ @str, @index = str, 0
5
5
  end
6
-
6
+
7
7
  def to_s
8
8
  @str
9
9
  end
10
-
11
- def rem()
12
- @str.length - @index
10
+
11
+ def rem()
12
+ @str.length - @index
13
13
  end
14
-
15
- def eof? ()
16
- rem <= 0
14
+
15
+ def eof? ()
16
+ rem <= 0
17
17
  end
18
-
19
- def skip(n)
20
- @index += n
18
+
19
+ def skip(n)
20
+ @index += n
21
21
  end
22
-
23
- def skip_padding()
24
- skip((4 - (@index % 4)) % 4)
22
+
23
+ def skip_padding()
24
+ skip((4 - (@index % 4)) % 4)
25
25
  end
26
-
26
+
27
27
  def getn(n)
28
28
  raise EOFError if rem < n
29
29
  s = @str[@index, n]
@@ -37,6 +37,5 @@ module OSC
37
37
  skip(1)
38
38
  c
39
39
  end
40
-
41
40
  end
42
41
  end
@@ -1,6 +1,5 @@
1
1
  module OSC
2
2
  class OSCArgument
3
-
4
3
  def initialize(val) @val = val end
5
4
 
6
5
  attr_accessor :val
@@ -9,7 +8,6 @@ module OSC
9
8
  def to_f() @val.to_f end
10
9
  def to_s() @val.to_s end
11
10
 
12
-
13
11
  private
14
12
  def padding(s)
15
13
  s + ("\000" * ((4 - (s.size % 4)) % 4))
@@ -3,53 +3,53 @@ require 'ostruct'
3
3
 
4
4
  module OSC
5
5
  class OSCPacket
6
-
6
+
7
7
  def self.messages_from_network( string )
8
8
  messages = []
9
9
  osc = new( string )
10
-
10
+
11
11
  if osc.bundle?
12
12
  bundle = osc.get_string
13
13
  time = osc.get_timestamp
14
-
14
+
15
15
  osc.get_bundle_messages.each do | message |
16
16
  messages << decode_simple_message( time, OSCPacket.new( message ) )
17
17
  end
18
-
18
+
19
19
  else
20
20
  messages << decode_simple_message( time, osc )
21
21
  end
22
-
22
+
23
23
  return messages
24
24
  end
25
-
25
+
26
26
  def self.decode_simple_message( time, osc_packet )
27
27
  address = osc_packet.get_string
28
- args = osc_packet.get_arguments
28
+ args = osc_packet.get_arguments
29
29
 
30
30
  Message.new_with_time(address, time, nil, *args )
31
31
  end
32
-
32
+
33
33
  def initialize( string )
34
34
  @packet = NetworkPacket.new( string )
35
-
36
- @types = { "i" => lambda{ OSCInt32.new( get_int32 ) },
35
+
36
+ @types = { "i" => lambda{ OSCInt32.new( get_int32 ) },
37
37
  "f" => lambda{ OSCFloat32.new( get_float32 ) },
38
38
  "s" => lambda{ OSCString.new( get_string ) },
39
39
  "b" => lambda{ OSCBlob.new( get_blob )}
40
40
  }
41
41
  end
42
-
42
+
43
43
  def get_bundle_messages
44
44
  bundle_messages = []
45
-
45
+
46
46
  until @packet.eof?
47
47
  l = @packet.getn(4).unpack('N')[0]
48
48
  bundle_messages << @packet.getn(l)
49
49
  end
50
50
  bundle_messages
51
51
  end
52
-
52
+
53
53
  def get_string
54
54
  result = ''
55
55
  until (c = @packet.getc) == string_delemeter
@@ -58,58 +58,58 @@ module OSC
58
58
  @packet.skip_padding
59
59
  result
60
60
  end
61
-
61
+
62
62
  def get_timestamp
63
63
  t1 = @packet.getn(4).unpack('N')[0]
64
64
  t2 = @packet.getn(4).unpack('N')[0]
65
65
  @packet.skip_padding
66
-
66
+
67
67
  if t1 == 0 && t2 == 1
68
68
  time = nil
69
69
  else
70
70
  time = t1 + t2.to_f / (2**32)
71
71
  end
72
-
72
+
73
73
  time
74
74
  end
75
-
75
+
76
76
  def get_arguments
77
77
  if @packet.getc == ?,
78
-
78
+
79
79
  tags = get_string
80
80
  args = []
81
-
81
+
82
82
  tags.scan(/./) do | tag |
83
83
  args << @types[tag].call
84
84
  end
85
85
  args
86
86
  end
87
87
  end
88
-
88
+
89
89
  def get_int32
90
90
  i = @packet.getn(4).unpack('N')[0]
91
91
  i -= 2**32 if i > (2**31-1)
92
92
  @packet.skip_padding
93
93
  i
94
94
  end
95
-
95
+
96
96
  def get_float32
97
97
  f = @packet.getn(4).unpack('g')[0]
98
98
  @packet.skip_padding
99
99
  f
100
100
  end
101
-
101
+
102
102
  def get_blob
103
103
  l = @packet.getn(4).unpack('N')[0]
104
104
  b = @packet.getn(l)
105
105
  @packet.skip_padding
106
106
  b
107
107
  end
108
-
108
+
109
109
  def bundle?
110
110
  !(@packet.to_s =~ /\A\#bundle/).nil?
111
111
  end
112
-
112
+
113
113
  def string_delemeter
114
114
  # ruby 1.9 has multicharacter support
115
115
  RUBY_VERSION.include?( '1.9' ) ? "\x00" : 0
@@ -2,30 +2,22 @@ require File.join( File.dirname( __FILE__ ), "osc_argument" )
2
2
 
3
3
  module OSC
4
4
  class OSCInt32 < OSCArgument
5
-
6
5
  def tag() 'i' end
7
6
  def encode() [@val].pack('N') end
8
-
9
7
  end
10
8
 
11
9
  class OSCFloat32 < OSCArgument
12
-
13
10
  def tag() 'f' end
14
11
  def encode() [@val].pack('g') end # fake - why fake?
15
-
16
12
  end
17
13
 
18
14
  class OSCString < OSCArgument
19
-
20
15
  def tag() 's' end
21
16
  def encode() padding(@val.sub(/\000.*\z/, '') + "\000") end
22
-
23
17
  end
24
18
 
25
19
  class OSCBlob < OSCArgument
26
-
27
20
  def tag() 'b' end
28
21
  def encode() padding([@val.size].pack('N') + @val) end
29
-
30
22
  end
31
23
  end
@@ -0,0 +1,43 @@
1
+ # sanity checks
2
+ require File.join( File.dirname(__FILE__) , '..', 'spec_helper' )
3
+
4
+ describe MessageBuilder do
5
+ before :each do
6
+ @builder = MessageBuilder.new
7
+ end
8
+
9
+ it "encodes just the address" do
10
+ mesg = @builder.with_address("/hi")
11
+ mesg.build.encode.should == "/hi\000,\000\000\000"
12
+ end
13
+
14
+ it "encodes single int values" do
15
+ mesg = @builder.with_address("/hi").
16
+ with_int(33)
17
+
18
+ mesg.build.encode.should == "/hi\000,i\000\000\000\000\000!"
19
+ end
20
+
21
+ it "encodes single string values" do
22
+ mesg = @builder.with_address("/hi").
23
+ with_string("hello")
24
+
25
+ mesg.build.encode.should == "/hi\000,s\000\000hello\000\000\000"
26
+ end
27
+
28
+ it "encodes single float values" do
29
+ mesg = @builder.with_address("/hi").
30
+ with_float(3.14159)
31
+
32
+ mesg.build.encode.should == "/hi\000,f\000\000@I\017\320"
33
+ end
34
+
35
+ it "encodes multiple floats" do
36
+ mesg = @builder.with_address("/hi").
37
+ with_float(3.14159).
38
+ with_float(4.5)
39
+
40
+ mesg.build.encode.should == [47, 104, 105, 0, 44, 102, 102, 0, 64, 73, 15, 208, 64, 144, 0, 0].pack("C*")
41
+ end
42
+
43
+ end
@@ -12,23 +12,47 @@ require File.join( File.dirname(__FILE__) , '..', 'spec_helper' )
12
12
 
13
13
 
14
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
15
+ describe "basic traits" do
16
+ it "should have no arguments if you define none" do
17
+ m = OSC::Message.new( "/hi" )
18
+ m.to_a.should == []
19
+ end
20
+
21
+ it "should accept int arguments" do
22
+ m = OSC::Message.new( "/hi", 42 )
23
+ m.to_a.should == [42]
24
+ m.tags.should == "i"
25
+ end
26
+
27
+ it "should accept string arguments" do
28
+ m = OSC::Message.new( "/hi", "42" )
29
+ m.to_a.should == ["42"]
30
+ m.tags.should == "s"
31
+ end
32
+
33
+ it "should accept float arguments" do
34
+ m = OSC::Message.new( "/hi", 42.001 )
35
+ m.to_a.should == [42.001]
36
+ m.tags.should == "f"
37
+ end
21
38
  end
22
39
 
23
- it "should have no arguments if you define none" do
24
- m = OSC::Message.new( "/hi" )
25
- m.to_a.should == []
26
- end
40
+ describe "more interesting traits" do
41
+ before :each do
42
+ @builder = MessageBuilder.new
43
+ @builder.with_int( 42 ).
44
+ with_int( 33 )
45
+
46
+ @message = @builder.build
47
+ end
27
48
 
28
- it "should have accept int arguments" do
29
- m = OSC::Message.new( "/hi", 42 )
30
- m.to_a.should == [42]
31
- m.tags.should == "i"
32
- end
49
+
33
50
 
51
+ it "should know equality" do
52
+ @message2 = @builder.build
53
+
54
+ @message.object_id.should_not == @message2.object_id
55
+ @message.should == @message2
56
+ end
57
+ end
34
58
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: osc-ruby
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.0
4
+ version: 0.6.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - aberant
@@ -9,11 +9,11 @@ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
 
12
- date: 2009-10-16 00:00:00 -05:00
12
+ date: 2009-12-03 00:00:00 -06:00
13
13
  default_executable:
14
14
  dependencies: []
15
15
 
16
- description:
16
+ description: a ruby client for the OSC protocol
17
17
  email: qzzzq1@gmail.com
18
18
  executables: []
19
19
 
@@ -38,11 +38,12 @@ files:
38
38
  - lib/osc-ruby/osc_argument.rb
39
39
  - lib/osc-ruby/osc_packet.rb
40
40
  - lib/osc-ruby/osc_types.rb
41
- - lib/osc-ruby/packet.rb
42
41
  - lib/osc-ruby/server.rb
43
42
  - README.rdoc
44
43
  has_rdoc: true
45
44
  homepage: http://github.com/aberant/osc-ruby
45
+ licenses: []
46
+
46
47
  post_install_message:
47
48
  rdoc_options:
48
49
  - --charset=UTF-8
@@ -63,14 +64,15 @@ required_rubygems_version: !ruby/object:Gem::Requirement
63
64
  requirements: []
64
65
 
65
66
  rubyforge_project: osc-ruby
66
- rubygems_version: 1.3.1
67
+ rubygems_version: 1.3.5
67
68
  signing_key:
68
- specification_version: 2
69
+ specification_version: 3
69
70
  summary: inital gem
70
71
  test_files:
71
72
  - spec/builders/message_builder.rb
72
73
  - spec/spec_helper.rb
73
74
  - spec/unit/address_pattern_spec.rb
75
+ - spec/unit/message_builder_spec.rb
74
76
  - spec/unit/message_bundle_spec.rb
75
77
  - spec/unit/message_spec.rb
76
78
  - spec/unit/network_packet_spec.rb
@@ -1,134 +0,0 @@
1
- module OSC
2
- class Packet
3
-
4
- class PO
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
24
-
25
- def getn(n)
26
- raise EOFError if rem < n
27
- s = @str[@index, n]
28
- skip(n)
29
- s
30
- end
31
-
32
- def getc
33
- raise EOFError if rem < 1
34
- c = @str[@index]
35
- skip(1)
36
- c
37
- end
38
- end
39
-
40
- def self.decode_int32(io)
41
- i = io.getn(4).unpack('N')[0]
42
- i -= 2**32 if i > (2**31-1)
43
- i
44
- end
45
-
46
- def self.decode_float32(io)
47
- f = io.getn(4).unpack('g')[0]
48
- f
49
- end
50
-
51
- def self.decode_string(io)
52
- s = ''
53
- until (c = io.getc) == 0
54
- s << c
55
- end
56
- io.skip_padding
57
- s
58
- end
59
-
60
- def self.decode_blob(io)
61
- l = io.getn(4).unpack('N')[0]
62
- b = io.getn(l)
63
- io.skip_padding
64
- b
65
- end
66
-
67
- def self.decode_timetag(io)
68
- t1 = io.getn(4).unpack('N')[0]
69
- t2 = io.getn(4).unpack('N')[0]
70
- [t1, t2]
71
- end
72
-
73
- def self.decode2(time, packet, list)
74
- io = PO.new(packet)
75
- id = decode_string(io)
76
- if id =~ /\A\#/
77
- if id == '#bundle'
78
- t1, t2 = decode_timetag(io)
79
- if t1 == 0 && t2 == 1
80
- time = nil
81
- else
82
- time = t1 + t2.to_f / (2**32)
83
- end
84
- until io.eof?
85
- l = io.getn(4).unpack('N')[0]
86
- s = io.getn(l)
87
- decode2(time, s, list)
88
- end
89
- end
90
- elsif id =~ /\//
91
- address = id
92
- if io.getc == ?,
93
- tags = decode_string(io)
94
- args = []
95
- tags.scan(/./) do |t|
96
- case t
97
- when 'i'
98
- i = decode_int32(io)
99
- args << OSCInt32.new(i)
100
- when 'f'
101
- f = decode_float32(io)
102
- args << OSCFloat32.new(f)
103
- when 's'
104
- s = decode_string(io)
105
- args << OSCString.new(s)
106
- when 'b'
107
- b = decode_blob(io)
108
- args << OSCBlob.new(b)
109
- when /[htd]/; io.read(8)
110
- when 'S'; decode_string(io)
111
- when /[crm]/; io.read(4)
112
- when /[TFNI\[\]]/;
113
- end
114
- end
115
- list << [time, Message.new(address, nil, *args)]
116
- end
117
- end
118
- end
119
-
120
- private_class_method :decode_int32,
121
- :decode_float32,
122
- :decode_string,
123
- :decode_blob,
124
- :decode_timetag,
125
- :decode2
126
-
127
- def self.decode(packet)
128
- list = []
129
- decode2(nil, packet, list)
130
- list
131
- end
132
-
133
- end
134
- end