ml-ruby 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/README ADDED
File without changes
data/lib/ml-ruby.rb ADDED
@@ -0,0 +1 @@
1
+ require 'ml-ruby/ml_client'
@@ -0,0 +1,192 @@
1
+ # ml_ruby: Ruby Bindings for the ML-Donkey GUI protocol
2
+ # Copyright (C) 2008 Jens Herrmann
3
+ #
4
+ # This program is free software; you can redistribute it and/or
5
+ # modify it under the terms of the GNU General Public License
6
+ # as published by the Free Software Foundation; either version 2
7
+ # of the License, or (at your option) any later version.
8
+ #
9
+ # This program is distributed in the hope that it will be useful,
10
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
11
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12
+ # GNU General Public License for more details.
13
+ #
14
+ # You should have received a copy of the GNU General Public License
15
+ # along with this program; if not, write to the Free Software
16
+ # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17
+
18
+ require 'socket'
19
+ include Socket::Constants
20
+ require File.dirname(__FILE__) + '/ml_protocol'
21
+
22
+ module ML_ruby
23
+ class ML_client
24
+
25
+ PROTOCOL_VERSION= 41
26
+ MAX_OPCODE_SENT= 59
27
+ MAX_OPCODE_RCVD= 68
28
+
29
+ TIME_OUT= 10
30
+
31
+ # public methods
32
+
33
+ def initialize host='localhost', port=4001, user=nil, password=nil
34
+ @listener= []
35
+ @send_queue= []
36
+ # ML_payload_handler::Types.keys.each do |opcode|
37
+ # add_listener opcode, self, :log
38
+ # end
39
+ connect host, port, user, password
40
+ end
41
+
42
+ def get_current_downloads
43
+ send_payload= ML_S_get_downloading_files.new( {} )
44
+ recv_payload= ML_R_downloading_files
45
+ send_and_wait_for send_payload, recv_payload
46
+ end
47
+
48
+ def get_finished_downloads
49
+ send_payload= ML_S_get_downloaded_files.new( {} )
50
+ recv_payload= ML_R_downloaded_files
51
+ send_and_wait_for send_payload, recv_payload
52
+ end
53
+
54
+ def start_download url
55
+ send_opcode= ML_S_download_url.class.opcode
56
+ sd= ML_message.new send_opcode, ML_S_download_url.new( :url=> url )
57
+ add_to_send_queue sd
58
+ end
59
+
60
+ protected
61
+
62
+
63
+
64
+ def send_and_wait_for send_payload, recv_payload
65
+ @data= nil
66
+ send_opcode=send_payload.class.opcode
67
+ recv_opcode=recv_payload.opcode
68
+ msg= ML_message.new send_opcode, send_payload
69
+ add_listener recv_opcode, self, :handle
70
+ add_to_send_queue msg
71
+ timer= Time.now
72
+ while ! @data && timer > Time.now - TIME_OUT # seconds ago
73
+ sleep 0.5
74
+ end
75
+ remove_listener recv_opcode, self, :handle
76
+ return @data.payload if @data
77
+ nil
78
+ end
79
+
80
+
81
+ def add_listener opcode, listener, method
82
+ # puts "Added: #{opcode}, #{listener}, #{method}"
83
+ @listener[opcode]= [] unless @listener[opcode]
84
+ @listener[opcode]<<[listener,method]
85
+ end
86
+
87
+ def remove_listener opcode, listener, method
88
+ # puts "removed: #{opcode}, #{listener}, #{method}"
89
+ @listener[opcode].delete [listener,method]
90
+ end
91
+
92
+ def add_to_send_queue msg
93
+ @send_queue<< msg
94
+ end
95
+
96
+ def handle msg
97
+ @data= msg
98
+ end
99
+
100
+ def log msg
101
+ # puts msg.inspect
102
+ end
103
+
104
+ private
105
+ def connect host, port, user, password
106
+ @socket = Socket.new( AF_INET, SOCK_STREAM, 0 )
107
+ sockaddr = Socket.pack_sockaddr_in( port, host )
108
+ @socket.connect( sockaddr )
109
+ if get_core_protocol
110
+ send_protocol_version
111
+ send_interested_in_sources
112
+ first_message= login user, password
113
+ if first_message.opcode.payload== ML_R_bad_password.opcode
114
+ raise "Wrong credentials"
115
+ end
116
+ do_handle @listener, first_message
117
+ Thread.abort_on_exception = true
118
+ @thread= Thread.new(@socket,@send_queue,@listener) do |socket,send_queue,listener|
119
+ loop do
120
+ msg_to_send= send_queue.shift
121
+ send_message msg_to_send if msg_to_send
122
+ msg_received= receive_message
123
+ do_handle listener, msg_received if msg_received
124
+ end
125
+ end
126
+ end
127
+ end
128
+
129
+ def receive_message
130
+ selected= select( [@socket], nil, nil, 0.5 )
131
+ if selected
132
+ socket= selected[0][0]
133
+ paket_size= ML_int32.decode( socket.recvfrom( ML_int32.size )[0])
134
+ end
135
+ result= nil
136
+ if paket_size
137
+ opcode= ML_int16.decode( socket.recvfrom( ML_int16.size )[0])
138
+ raw_data= socket.recvfrom( paket_size.payload - opcode.size )
139
+ handler= ML_payload_handler.for( opcode.payload )
140
+ unless handler
141
+ result=ML_message.new opcode, ML_R_unknown.new( {:raw_data=> raw_data.inspect } )
142
+ else
143
+ payload= ML_payload_handler.for( opcode.payload ).decode( raw_data[0] )
144
+ result=ML_message.new opcode, payload
145
+ end
146
+ end
147
+ return result
148
+ end
149
+
150
+ def send_message msg
151
+ @socket.write msg.encode
152
+ end
153
+
154
+ def do_handle listener, msg
155
+ listener= listener[msg.opcode.payload]
156
+ listener.each do |l,method|
157
+ l.send method, msg
158
+ end if listener
159
+ end
160
+
161
+ # Handling of basic messages for starting connection
162
+
163
+ def get_core_protocol
164
+ cp= receive_message
165
+
166
+ return cp.opcode.payload==ML_R_core_protocol.opcode &&
167
+ cp.payload.max_protocol_version.payload>= PROTOCOL_VERSION &&
168
+ cp.payload.max_opcode_sent.payload>= MAX_OPCODE_SENT &&
169
+ cp.payload.max_opcode_rcvd.payload>= MAX_OPCODE_RCVD
170
+ end
171
+
172
+ def send_protocol_version
173
+ opcode= 0
174
+ pv= ML_message.new opcode, ML_S_protocol_version.new( :protocol_version=>PROTOCOL_VERSION )
175
+ send_message pv
176
+ end
177
+
178
+ def send_interested_in_sources
179
+ opcode= 64
180
+ pv= ML_message.new opcode, ML_S_interested_in_sources.new( :interested_in_sources=>0 )
181
+ send_message pv
182
+ end
183
+
184
+ def login user, password
185
+ opcode= 52
186
+ login_msg= ML_message.new opcode, ML_S_password.new( {:password=>password, :login_name=>user} )
187
+ send_message login_msg
188
+ receive_message
189
+ end
190
+
191
+ end
192
+ end
@@ -0,0 +1,339 @@
1
+ # ml_ruby: Ruby Bindings for the ML-Donkey GUI protocol
2
+ # Copyright (C) 2008 Jens Herrmann
3
+ #
4
+ # This program is free software; you can redistribute it and/or
5
+ # modify it under the terms of the GNU General Public License
6
+ # as published by the Free Software Foundation; either version 2
7
+ # of the License, or (at your option) any later version.
8
+ #
9
+ # This program is distributed in the hope that it will be useful,
10
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
11
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12
+ # GNU General Public License for more details.
13
+ #
14
+ # You should have received a copy of the GNU General Public License
15
+ # along with this program; if not, write to the Free Software
16
+ # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17
+
18
+ module ML_ruby
19
+ class ML_atom
20
+ attr_reader :payload
21
+ def initialize payload
22
+ @payload= payload
23
+ end
24
+ def size
25
+ self.class.size
26
+ end
27
+ def self.size
28
+ @size
29
+ end
30
+ def self.packstring
31
+ @packstring
32
+ end
33
+ def encode
34
+ [ @payload ].pack self.class.packstring
35
+ end
36
+ def self.decode data
37
+ self.new( data.unpack( self.packstring )[0] )
38
+ end
39
+ def inspect
40
+ "#{self.class.name}: #{@payload}"
41
+ end
42
+ def == other
43
+ false if not other
44
+ @payload== other.payload
45
+ end
46
+ end
47
+
48
+ class ML_int64 < ML_atom; @size= 8; @packstring= 'Q'; end
49
+ class ML_int32 < ML_atom; @size= 4; @packstring= 'L'; end
50
+ class ML_uint32 < ML_atom; @size= 4; @packstring= 'L'; end
51
+ class ML_int16 < ML_atom; @size= 2; @packstring= 'S'; end
52
+ class ML_int8 < ML_atom; @size= 1; @packstring= 'C'; end
53
+ class ML_char < ML_atom; @size= 1; @packstring= 'a'; end
54
+ class ML_char16 < ML_atom; @size= 16; @packstring= 'a16'; end
55
+
56
+ class ML_list
57
+ attr_reader :payload
58
+ def initialize payload
59
+ @payload= payload
60
+ end
61
+ def size
62
+ ML_int16.size + @payload.inject( 0 ) {|sum,elem| sum+elem.size}
63
+ end
64
+ def encode
65
+ ML_int16.new( @payload.size ).encode + @payload.inject("") {|sum,elem| sum+elem.encode }
66
+ end
67
+ def self.decode data
68
+ # puts self.name, data.inspect
69
+ len= ML_int16.decode data
70
+ data= data[len.size..-1]
71
+ result=[]
72
+ len.payload.times do
73
+ elem= @type.decode( data )
74
+ # puts self.name, elem.to_yaml
75
+ result<< elem
76
+ data= data[elem.size..-1]
77
+ end
78
+ self.new result
79
+ end
80
+ def == other
81
+ false unless other
82
+ payload == other.payload
83
+ end
84
+ end
85
+
86
+ class ML_string < ML_list
87
+ @type= ML_char
88
+ def initialize payload
89
+ if payload.is_a?( Array )
90
+ super payload
91
+ else
92
+ @payload= payload.scan(/./).inject([]) {|sum,char| sum<< ML_char.new( char ) }
93
+ end
94
+ end
95
+ def payload
96
+ @payload.map {|c|c.payload}.join
97
+ end
98
+ def inspect
99
+ "#{self.class.name}: \"#{payload}\""
100
+ end
101
+ end
102
+
103
+ class ML_float < ML_string
104
+ @type= ML_char
105
+ def initialize payload
106
+ # puts payload.inspect
107
+ unless payload.is_a? Array
108
+ if (payload*100).to_i % 10 == 0
109
+ payload= payload.to_s + "0"
110
+ else
111
+ payload= payload.to_s.gsub(/\.0/,'.')
112
+ end
113
+ end
114
+ super payload
115
+ end
116
+ def payload
117
+ @payload.map {|c|c.payload}.join.gsub(/\.(\d)$/,'.0\1').to_f
118
+ end
119
+ end
120
+
121
+ class ML_list_of_int16 < ML_list
122
+ @type= ML_int16
123
+ end
124
+ class ML_list_of_int32 < ML_list
125
+ @type= ML_int32
126
+ end
127
+ class ML_list_of_string < ML_list
128
+ @type= ML_string
129
+ end
130
+
131
+ class ML_compound
132
+ def self.attributes
133
+ @attributes
134
+ end
135
+ def self.conditions
136
+ @conditions
137
+ end
138
+ def initialize data
139
+ self.class.attributes.each do |attr,type|
140
+ set_compound_attribute( attr, data[attr], type )
141
+ end
142
+ if self.class.conditions
143
+ self.class.conditions.each do |test,extra|
144
+ key=data[test].payload
145
+ extra[key].each do |attr,type|
146
+ set_compound_attribute( attr, data[attr], type )
147
+ end if extra[key]
148
+ end
149
+ end
150
+ end
151
+ def size
152
+ self.class.attributes.inject( 0 ) { |sum,attr| sum+send( attr[0] ).size }
153
+ end
154
+ def encode
155
+ result=""
156
+ self.class.attributes.each do |attr,type|
157
+ result<<( send( attr ).encode )
158
+ end
159
+ if self.class.conditions
160
+ # puts attributes.inspect
161
+ self.class.conditions.each do |test,extra|
162
+ # puts "testing #{[test,extra].inspect}"
163
+ key= send( test ).payload
164
+ extra[key].each do |attr,type|
165
+ result<<( send( attr ).encode )
166
+ end if extra[key]
167
+ end
168
+ end
169
+ result
170
+ end
171
+ def self.decode data
172
+ # puts data.inspect
173
+ attributes={}
174
+ self.attributes.each do |attr,type|
175
+ attributes[attr]= type.decode data
176
+ data= data[attributes[attr].size..-1]
177
+ end
178
+ if conditions
179
+ # puts attributes.inspect
180
+ conditions.each do |test,extra|
181
+ # puts "testing #{[test,extra].inspect}"
182
+ key= attributes[test].payload
183
+ extra[key].each do |attr,type|
184
+ attributes[attr]= type.decode data
185
+ data= data[attributes[attr].size..-1]
186
+ end if extra[key]
187
+ end
188
+ end
189
+ self.new attributes
190
+ end
191
+ protected
192
+ def self.attr_reader *sym
193
+ super *sym
194
+ end
195
+ def set_compound_attribute( attr, value, type )
196
+ # puts [attr, value, type].inspect
197
+ self.class.attr_reader attr
198
+ if value.is_a? type
199
+ eval "@#{attr}= value"
200
+ else
201
+ eval "@#{attr}= #{type}.new value"
202
+ end
203
+ end
204
+ end
205
+
206
+ class ML_filestate < ML_compound
207
+ @attributes= [
208
+ [:state,ML_int8],
209
+ ]
210
+ @conditions= [[:state,
211
+ { 6=>[
212
+ [:reason,ML_string],
213
+ ]
214
+ },
215
+ ]]
216
+ end
217
+
218
+ class ML_availability < ML_compound
219
+ @attributes= [
220
+ [:network,ML_int32],
221
+ [:chunks,ML_string],
222
+ ]
223
+ end
224
+ class ML_list_of_availability < ML_list
225
+ @type= ML_availability
226
+ end
227
+
228
+ class ML_ogg_stream_tags < ML_compound
229
+ @attributes=[
230
+ # TODO: http://mldonkey.sourceforge.net/GuiOGGStreamTag
231
+ ]
232
+ end
233
+ class ML_list_of_ogg_stream_tags < ML_list
234
+ @type= ML_ogg_stream_tags
235
+ end
236
+ class ML_ogg_stream < ML_compound
237
+ @attributes=[
238
+ [:number=>ML_int32],
239
+ [:type=>ML_int8],
240
+ [:tags=>ML_list_of_ogg_stream_tags]
241
+ ]
242
+ end
243
+
244
+ class ML_list_of_ogg_stream < ML_list
245
+ @type= ML_ogg_stream
246
+ end
247
+
248
+ class ML_subfile < ML_compound
249
+ @attributes=[
250
+ [:name=>ML_string],
251
+ [:size=>ML_int64],
252
+ [:format=>ML_string]
253
+ ]
254
+ end
255
+
256
+ class ML_list_of_subfile < ML_list
257
+ @type= ML_subfile
258
+ end
259
+
260
+ class ML_comment < ML_compound
261
+ @attributes=[
262
+ [:ip=>ML_int32],
263
+ [:geo_ip=>ML_int8],
264
+ [:name=>ML_string],
265
+ [:rating=>ML_int64],
266
+ [:comment=>ML_string]
267
+ ]
268
+ end
269
+
270
+ class ML_list_of_comment < ML_list
271
+ @type= ML_comment
272
+ end
273
+
274
+ class ML_fileformat < ML_compound
275
+ @attributes= [
276
+ [:format,ML_int8],
277
+ ]
278
+ @conditions= [[:format,
279
+ { 1=>[
280
+ [:extension,ML_string],
281
+ [:kind,ML_string],
282
+ ],
283
+ 2=>[
284
+ [:codec=>ML_string],
285
+ [:width=>ML_int32],
286
+ [:height=>ML_int32],
287
+ [:fps=>ML_int32],
288
+ [:rate=>ML_int32],
289
+ ],
290
+ 3=>[
291
+ [:mp3_title=>ML_string],
292
+ [:mp3_artist=>ML_string],
293
+ [:mp3_album=>ML_string],
294
+ [:mp3_year=>ML_string],
295
+ [:mp3_comment=>ML_string],
296
+ [:mp3_tracknum=>ML_int32],
297
+ [:mp3_genre=>ML_int32],
298
+ ],
299
+ 4=>[
300
+ [:stream=>ML_list_of_ogg_stream]
301
+ ]
302
+ },
303
+ ]]
304
+ end
305
+
306
+ class ML_fileinfo < ML_compound
307
+ @attributes= [
308
+ [:id, ML_int32],
309
+ [:network_id, ML_int32],
310
+ [:file_names, ML_list_of_string],
311
+ [:md4, ML_char16],
312
+ [:file_size,ML_int64],
313
+ [:downloaded,ML_int64],
314
+ [:sources,ML_int32],
315
+ [:clients,ML_int32],
316
+ [:state,ML_filestate],
317
+ [:chunks,ML_string],
318
+ [:availability,ML_list_of_availability],
319
+ [:speed,ML_float],
320
+ [:chunks_ages,ML_list_of_int32],
321
+ [:file_age,ML_int32],
322
+ [:file_format,ML_fileformat],
323
+ [:preferred_name,ML_string],
324
+ [:last_seen,ML_int32],
325
+ [:priority,ML_uint32],
326
+ [:comment,ML_string],
327
+ [:links,ML_list_of_string],
328
+ [:subfiles,ML_list_of_subfile],
329
+ [:file_format_im,ML_string],
330
+ [:comments,ML_list_of_comment],
331
+ [:file_user,ML_string],
332
+ [:file_group,ML_string],
333
+ ]
334
+ end
335
+
336
+ class ML_list_of_fileinfo < ML_list
337
+ @type= ML_fileinfo
338
+ end
339
+ end
@@ -0,0 +1,161 @@
1
+ # ml_ruby: Ruby Bindings for the ML-Donkey GUI protocol
2
+ # Copyright (C) 2008 Jens Herrmann
3
+ #
4
+ # This program is free software; you can redistribute it and/or
5
+ # modify it under the terms of the GNU General Public License
6
+ # as published by the Free Software Foundation; either version 2
7
+ # of the License, or (at your option) any later version.
8
+ #
9
+ # This program is distributed in the hope that it will be useful,
10
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
11
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12
+ # GNU General Public License for more details.
13
+ #
14
+ # You should have received a copy of the GNU General Public License
15
+ # along with this program; if not, write to the Free Software
16
+ # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17
+
18
+ require File.dirname(__FILE__) + '/ml_data_types'
19
+
20
+ module ML_ruby
21
+ class ML_payload < ML_compound
22
+ def self.opcode
23
+ @opcode
24
+ end
25
+ end
26
+
27
+ class ML_message
28
+ attr_reader :size, :opcode, :payload
29
+ def initialize opcode=nil, payload=nil
30
+ if opcode && opcode.is_a?( ML_int16 )
31
+ @opcode= opcode
32
+ elsif opcode
33
+ @opcode= ML_int16.new( opcode )
34
+ end
35
+ @payload= payload if payload
36
+ @size= ML_int32.new( @opcode.size + (payload ? payload.size : 0) ) if opcode
37
+ end
38
+ def encode
39
+ @size.encode + @opcode.encode + @payload.encode
40
+ end
41
+ end
42
+
43
+ class ML_S_protocol_version < ML_payload
44
+ @opcode= 0
45
+ @attributes= [
46
+ [:protocol_version,ML_int32]
47
+ ]
48
+ end
49
+
50
+ class ML_S_interested_in_sources < ML_payload
51
+ @opcode= 64
52
+ @attributes= [
53
+ [:interested_in_sources,ML_int8]
54
+ ]
55
+ end
56
+
57
+ class ML_S_password < ML_payload
58
+ @opcode= 52
59
+ @attributes= [
60
+ [:password,ML_string],
61
+ [:login_name,ML_string],
62
+ ]
63
+ end
64
+
65
+ class ML_S_get_downloading_files < ML_payload
66
+ @opcode= 45
67
+ @attributes= [
68
+ ]
69
+ end
70
+
71
+ class ML_S_get_downloaded_files < ML_payload
72
+ @opcode= 46
73
+ @attributes= [
74
+ ]
75
+ end
76
+
77
+ class ML_S_download_url< ML_payload
78
+ @opcode= 8
79
+ @attributes= [
80
+ [:url,ML_string],
81
+ ]
82
+ end
83
+
84
+ class ML_R_core_protocol < ML_payload
85
+ @opcode= 0
86
+ @attributes= [
87
+ [:max_protocol_version,ML_int32],
88
+ [:max_opcode_sent,ML_int32],
89
+ [:max_opcode_rcvd,ML_int32],
90
+ ]
91
+ end
92
+
93
+ class ML_R_network_info < ML_payload
94
+ @opcode= 20
95
+ @attributes= [
96
+ [:network_identifier,ML_int32],
97
+ [:network_name,ML_string],
98
+ [:enabled,ML_int8],
99
+ [:config_file,ML_string],
100
+ [:uploaded,ML_int64],
101
+ [:downloaded,ML_int64],
102
+ [:connected_servers,ML_int32],
103
+ [:network_flags,ML_list_of_int16],
104
+ ]
105
+ end
106
+
107
+ class ML_R_console_message < ML_payload
108
+ @opcode= 19
109
+ @attributes= [
110
+ [:message,ML_string],
111
+ ]
112
+ end
113
+
114
+ class ML_R_bad_password < ML_payload
115
+ @opcode= 47
116
+ @attributes= [
117
+ ]
118
+ end
119
+
120
+ class ML_R_fileinfo < ML_payload
121
+ @opcode= 52
122
+ @attributes= [
123
+ [:fileinfo,ML_fileinfo],
124
+ ]
125
+ end
126
+
127
+ class ML_R_downloading_files < ML_payload
128
+ @opcode= 53
129
+ @attributes= [
130
+ [:list,ML_list_of_fileinfo],
131
+ ]
132
+ end
133
+
134
+ class ML_R_downloaded_files < ML_payload
135
+ @opcode= 54
136
+ @attributes= [
137
+ [:list,ML_list_of_fileinfo],
138
+ ]
139
+ end
140
+
141
+ class ML_R_unknown < ML_payload
142
+ @attributes= [
143
+ [:raw_data,ML_string],
144
+ ]
145
+ end
146
+
147
+ class ML_payload_handler
148
+ Types={
149
+ 0 => ML_R_core_protocol,
150
+ 19 => ML_R_console_message,
151
+ 20 => ML_R_network_info,
152
+ 47 => ML_R_bad_password,
153
+ 52 => ML_R_fileinfo,
154
+ 53 => ML_R_downloading_files,
155
+ 54 => ML_R_downloaded_files,
156
+ }
157
+ def self.for opcode
158
+ Types[opcode]
159
+ end
160
+ end
161
+ end
data/rakefile.rb ADDED
@@ -0,0 +1,49 @@
1
+ require 'rake'
2
+ require 'rake/testtask'
3
+ require 'rake/rdoctask'
4
+ require 'rake/gempackagetask'
5
+
6
+ task :default => :test
7
+
8
+ desc "Run the tests"
9
+ Rake::TestTask::new do |t|
10
+ t.test_files = FileList['test/test*.rb']
11
+ t.verbose = true
12
+ end
13
+
14
+ desc "Generate the documentation"
15
+ Rake::RDocTask::new do |rdoc|
16
+ rdoc.rdoc_dir = 'ml-ruby-doc/'
17
+ rdoc.title = "ML-Ruby Documentation"
18
+ rdoc.options << '--line-numbers' << '--inline-source'
19
+ rdoc.rdoc_files.include('README')
20
+ rdoc.rdoc_files.include('lib/**/*.rb')
21
+ end
22
+
23
+ spec = Gem::Specification::new do |s|
24
+ s.platform = Gem::Platform::RUBY
25
+
26
+ s.name = 'ml-ruby'
27
+ s.version = "0.0.1"
28
+ s.summary = "ML Ruby are the ruby bindings for the open source peer 2 peer software MLDonkey. This is the first part of an alternative to the official web GUI written in Ruby On Rails."
29
+ s.description = <<EOF
30
+ EOF
31
+ s.author = 'Jens Herrmann'
32
+ s.email = 'interesse@rubyforge.org'
33
+ s.homepage = "http://rubyforge.org/projects/ml-ruby/"
34
+
35
+ s.requirements << 'none'
36
+ s.require_path = 'lib'
37
+ s.files = FileList["lib/**/*.rb","test/**/*.rb", "README","rakefile.rb"]
38
+ s.test_files = FileList['test/test*.rb']
39
+
40
+ s.has_rdoc = true
41
+ s.extra_rdoc_files = ["README"]
42
+ s.rdoc_options.concat ['--main', 'README']
43
+ end
44
+
45
+ desc "Package the library as a gem"
46
+ Rake::GemPackageTask.new(spec) do |pkg|
47
+ pkg.need_zip = true
48
+ pkg.need_tar = true
49
+ end
@@ -0,0 +1,42 @@
1
+ $:.unshift(File.dirname(__FILE__) + '/../lib')
2
+
3
+ require 'ml-ruby'
4
+ require 'test/unit'
5
+
6
+ include ML_ruby
7
+
8
+ class TestDatatypes <Test::Unit::TestCase
9
+
10
+ def test_atom_inspect
11
+ assert_equal "ML_ruby::ML_atom: 0", ML_atom.new(0).inspect
12
+ end
13
+
14
+ def test_int64
15
+ assert_equal 0, ML_int64.decode( ML_int64.new(0).encode ).payload
16
+ end
17
+
18
+ def test_simple
19
+ [ML_int64,ML_int32,ML_uint32,ML_int16,ML_int8,].each do |type|
20
+ assert_equal 0, type.decode( type.new(0).encode ).payload
21
+ end
22
+ assert_equal "T", ML_char.decode( ML_char.new("T").encode ).payload
23
+ assert_equal "0123456789abcdef", ML_char16.decode( ML_char16.new("0123456789abcdef").encode ).payload
24
+ end
25
+
26
+ def test_string
27
+ assert_equal "Test", ML_string.decode( ML_string.new("Test").encode ).payload
28
+ end
29
+
30
+ def test_float
31
+ assert_equal 0.0, ML_float.decode( ML_float.new(0.0).encode ).payload
32
+ assert_equal 0.1, ML_float.decode( ML_float.new(0.1).encode ).payload
33
+ assert_equal 0.01, ML_float.decode( ML_float.new(0.01).encode ).payload
34
+ end
35
+
36
+ def test_list_of
37
+ assert_equal [ML_int16.new(0),ML_int16.new(1)], ML_list_of_int16.decode( ML_list_of_int16.new([ML_int16.new(0),ML_int16.new(1)]).encode ).payload
38
+ assert_equal [ML_int32.new(0),ML_int32.new(1)], ML_list_of_int32.decode( ML_list_of_int32.new([ML_int32.new(0),ML_int32.new(1)]).encode ).payload
39
+ assert_equal [ML_string.new('null'),ML_string.new('eins')], ML_list_of_string.decode( ML_list_of_string.new([ML_string.new('null'),ML_string.new('eins')]).encode ).payload
40
+ end
41
+
42
+ end
metadata ADDED
@@ -0,0 +1,60 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: ml-ruby
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Jens Herrmann
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2008-02-20 00:00:00 +01:00
13
+ default_executable:
14
+ dependencies: []
15
+
16
+ description: ""
17
+ email: interesse@rubyforge.org
18
+ executables: []
19
+
20
+ extensions: []
21
+
22
+ extra_rdoc_files:
23
+ - README
24
+ files:
25
+ - lib/ml-ruby/ml_client.rb
26
+ - lib/ml-ruby/ml_data_types.rb
27
+ - lib/ml-ruby/ml_protocol.rb
28
+ - lib/ml-ruby.rb
29
+ - test/test_datatypes.rb
30
+ - README
31
+ - rakefile.rb
32
+ has_rdoc: true
33
+ homepage: http://rubyforge.org/projects/ml-ruby/
34
+ post_install_message:
35
+ rdoc_options:
36
+ - --main
37
+ - README
38
+ require_paths:
39
+ - lib
40
+ required_ruby_version: !ruby/object:Gem::Requirement
41
+ requirements:
42
+ - - ">="
43
+ - !ruby/object:Gem::Version
44
+ version: "0"
45
+ version:
46
+ required_rubygems_version: !ruby/object:Gem::Requirement
47
+ requirements:
48
+ - - ">="
49
+ - !ruby/object:Gem::Version
50
+ version: "0"
51
+ version:
52
+ requirements:
53
+ - none
54
+ rubyforge_project:
55
+ rubygems_version: 1.0.1
56
+ signing_key:
57
+ specification_version: 2
58
+ summary: ML Ruby are the ruby bindings for the open source peer 2 peer software MLDonkey. This is the first part of an alternative to the official web GUI written in Ruby On Rails.
59
+ test_files:
60
+ - test/test_datatypes.rb