Permalink
Browse files

+ monster commit (sry): moved to specs, added a wrapping pure ruby

                        class to handle charset issues, more specs, ...
  • Loading branch information...
1 parent 831f695 commit 8c5afe1e188243f748b226109c93e5b145bb55cf @niko committed Jan 1, 2011
View
@@ -16,11 +16,56 @@ h2. Usage
See example.rb. Run it like
- ./example.rb test/test.mp3
+ ./example.rb spec/test.mp3
+
+h2. Ruby 1.9 and encoding
+
+Ruby 1.9 features really good encoding support: Each string has it's own explicit encoding. The default encoding for Icecast is ISO-8859-1 for station data and meta data.
+
+In order to make ruby-shout play nice with ruby 1.9 all I added a Shout#charset setter and all string accessors for station data are wrapped:
+
+* setters convert the given string to the given charset
+* and store the original string, available under #original_..., for example #original_description. This is done because converting may alter your string (characters incompatible with conversion are just swallowed). That way you are able to get your original string back (should you need it) and the getter is enabled to:
+* getters convert the value back to the original encoding, determined by the #original_... method.
+
+The idea is: We want to guaranty that strings keep their encoding when assigning them via a Shout accessor. In case strings are not compatible with Icecasts charset we want to degrade as gracefully as possible. IMHO just dropping incompatible characters does this best (when being listed in an external YP directory these "???br?" things just look awful). If you want to make sure this doesn't happen you have to compare the value before and after assigning it (or just compare for example #description with #original_description).
+
+h3. Synopsis:
+
+ s = Shout.new
+ s.charset = 'UTF-8'
+ s.description = 'dikşîne MUSłϾ'
+ puts s.description # => 'dikşîne MUSłϾ'
+
+ s = Shout.new
+ s.charset = 'ISO-8859-1' # this is the default
+ s.description = 'dikşîne MUSłϾ'
+ puts s.description # => 'dikîne MUSłϾ'
+ puts s.original_description # => 'dikşîne MUSłϾ'
+
+h3. Icecast charset config
+
+If you use s/th else than ISO-8859-1 you should configure your icecast accordingly: In the mount section set the charset:
+
+ <mount>
+ <mount-name>/your_station</mount-name>
+ <charset>UTF-8</charset>
+ ...
+ </mount>
+
+or (in the latest icecast builds)
+
+ <mount>
+ <mount-name>/*</mount-name>
+ <charset>UTF-8</charset>
+ ...
+ </mount>
+
+to set UTF-8 for all mountpoints.
h2. Todo
-* proper unit tests (blush)
+* proper unit tests (blush) ; working on that
h2. History & Credits
@@ -39,6 +84,8 @@ h2. Recent Changes
rake test:integration
+* Added Ruby 1.9 encoding support.
+
h2. State
I tested this version of ruby-shout to build and run on
View
@@ -1,13 +1,14 @@
require 'rubygems'
require 'rake/gempackagetask'
+require 'spec/rake/spectask'
-task :default => [:test]
+$TESTING_MINIUNIT = true
-namespace :test do
- desc "run the build integration test"
- task :integration do
- ruby "test/integration-test.rb"
- end
+desc "Run spec with specdoc output"
+Spec::Rake::SpecTask.new do |t|
+ spec_files = Dir.glob('spec/*_spec.rb')
+ t.spec_files = spec_files
+ t.spec_opts << '--format specdoc -c'
end
begin
@@ -21,7 +22,7 @@ begin
s.authors = ["Jared Jennings", "Niko Dittmann"]
s.require_paths = ["lib"]
s.rubyforge_project = 'ruby-shout'
- s.files = FileList["[A-Z]*", "{ext}/*"]
+ s.files = FileList["[A-Z]*", "{ext}/*", "{lib}/*"]
end
rescue LoadError
View
@@ -1,33 +1,39 @@
+# -*- encoding : utf-8 -*-
+
#!/usr/bin/env ruby
# Stream all the files given on the commandline to the Icecast server on localhost.
#
# Use the mp3 in the test directory:
#
-# ./example.rb test/test.mp3
+# ./example.rb spec/test.mp3
-require 'rubygems'
-require 'shout'
+BASE_DIR = File.expand_path File.dirname(__FILE__)
+VERSION = File.open(File.join(BASE_DIR, 'VERSION')).readline.strip
+require File.join(BASE_DIR, "spec/test_gem_installation/gems/ruby-shout-#{VERSION}/lib/shout")
BLOCKSIZE = 16384
s = Shout.new
-s.host = "localhost"
-s.port = 8000
s.mount = "/example"
+# s.charset = "UTF-8"
+# s.mount = "/utf8"
+s.host = "192.168.178.34"
s.user = "source"
s.pass = "hackme"
s.format = Shout::MP3
+s.description ='çaffé düdeldø … dikşîne ΞŁΞϾТЯФЛłϾ MUSłϾ ☼ ☺'
s.connect
-puts "open VLC and open network -> http://localhost:8000/example"
+puts "open VLC and open network -> http://#{s.host}:#{s.port}/example"
ARGV.each do |filename|
File.open(filename) do |file|
puts "sending data from #{filename}"
m = ShoutMetadata.new
m.add 'filename', filename
+ m.add 'title', 'title ☼ ☺'
s.metadata = m
while data = file.read(BLOCKSIZE)
View
@@ -5,7 +5,7 @@
have_library("vorbis", "vorbis_dsp_clear")
have_library("pthread", "pthread_create")
if find_library("shout", "shout_init","/usr","/usr/local") and have_header("shout/shout.h")
- create_makefile("shout")
+ create_makefile("shout_ext")
else
print "*** ERROR: need to have libshout and shout/shout.h to compile this module\n"
end
@@ -662,7 +662,7 @@ VALUE _sh_metadata_eq(VALUE self, VALUE meta) {
----------------------------------------------------------------
*/
-void Init_shout()
+void Init_shout_ext()
{
cShout = rb_define_class("Shout", rb_cObject);
View
@@ -0,0 +1,49 @@
+$LOAD_PATH << File.expand_path(File.dirname(__FILE__))
+require 'shout_ext'
+require 'shout/string_extension_rb_18'
+
+class Shout
+ attr_accessor :charset
+
+ INT_ACCESSORS = :port, :format
+ STRING_ACCESSORS = :host, :user, :username, :pass, :password, :protocol, :mount, :dumpfile,
+ :agent, :user_agent, :public, :name, :url, :genre, :description
+
+ STRING_ACCESSORS.each do |accessor|
+ attr_accessor :"original_#{accessor}"
+
+ alias :"raw_#{accessor}" :"#{accessor}"
+ define_method accessor do
+ return nil unless orig_acc = self.__send__("original_#{accessor}")
+
+ decode self.__send__(:"raw_#{accessor}"), orig_acc.encoding.name
+ end
+
+ alias :"raw_#{accessor}=" :"#{accessor}="
+ define_method :"#{accessor}=" do |value|
+ self.__send__ "original_#{accessor}=", value
+
+ self.__send__ :"raw_#{accessor}=", encode(value)
+ end
+ end
+
+ alias :ext_initialize :initialize
+ def initialize(opts={})
+ ext_initialize
+
+ self.charset = opts[:charset] || 'ISO-8859-1'
+
+ accessors = STRING_ACCESSORS + INT_ACCESSORS + [:charset]
+ a_opts = opts.select{ |k,v| accessors.include? k }
+
+ a_opts.each{ |k,v| self.__send__ :"#{k}=", v }
+ end
+
+ private
+ def encode(s)
+ s.encode(charset, :invalid => :replace, :undef => :replace, :replace => '')
+ end
+ def decode(s, orig_charset)
+ s.encode(orig_charset, charset, :invalid => :replace, :undef => :replace, :replace => '')
+ end
+end
@@ -0,0 +1,7 @@
+class String
+
+ def encode(*)
+ self
+ end
+
+end
View
@@ -9,7 +9,7 @@ Gem::Specification.new do |s|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
s.authors = ["Jared Jennings", "Niko Dittmann"]
- s.date = %q{2010-12-20}
+ s.date = %q{2011-01-01}
s.description = %q{Ruby bindings for libshout 2, a "Library which can be used to write a source client like ices" for Icecast (http://www.icecast.org/download.php).}
s.email = %q{mail@niko-dittmann.com}
s.extensions = ["ext/extconf.rb"]
@@ -21,7 +21,8 @@ Gem::Specification.new do |s|
"Rakefile",
"VERSION",
"ext/extconf.rb",
- "ext/shout.c"
+ "ext/shout_ext.c",
+ "lib/shout.rb"
]
s.homepage = %q{http://github.com/niko/ruby-shout}
s.rdoc_options = ["--charset=UTF-8"]
@@ -30,7 +31,10 @@ Gem::Specification.new do |s|
s.rubygems_version = %q{1.3.7}
s.summary = %q{Send audio over the network to an Icecast server}
s.test_files = [
- "test/integration-test.rb"
+ "spec/accessors_spec.rb",
+ "spec/build_spec.rb",
+ "spec/integration_spec.rb",
+ "spec/spec_helper.rb"
]
if s.respond_to? :specification_version then
View
@@ -0,0 +1,24 @@
+# -*- encoding : utf-8 -*-
+
+require File.join(File.expand_path(File.dirname(__FILE__)), 'spec_helper')
+
+describe "Accessors" do
+ before(:each) do
+ @shout = Shout.new
+ @description = 'çaffé düdeldø'
+ @genre = 'foobar'.encode('ISO-8859-1')
+ @shout.genre = @genre
+ @shout.description = @description
+ end
+ it "should not change the original encoding" do
+ @shout.description.encoding.should == @description.encoding
+ @shout.genre.encoding.should == @genre.encoding
+ end
+ describe "#original_..." do
+ it "should store the original value" do
+ @shout.original_description.should == @description
+ @shout.original_genre.should == @genre
+ end
+ end
+end
+
View
@@ -0,0 +1,44 @@
+require 'spec'
+
+BASE_DIR = File.expand_path File.join(File.dirname(__FILE__), '..')
+VERSION = File.open(File.join(BASE_DIR, 'VERSION')).readline.strip
+
+describe "Build process" do
+ def remove_pkg
+ command = %Q{
+ cd #{BASE_DIR}
+ rm -rf pkg
+ }
+ c = `#{command}`
+ puts c
+ return c
+ end
+
+ def clean_test_gem
+ command = %Q{
+ cd #{BASE_DIR}
+ rm -rf spec/test_gem_installation
+ }
+ c = `#{command}`
+ puts c
+ return c
+ end
+
+ def install_gem
+ command = %Q{
+ cd #{BASE_DIR}
+ rake build
+ gem install --no-test --no-rdoc --no-ri --install-dir spec/test_gem_installation --bindir spec/test_gem_installation pkg/ruby-shout-#{VERSION}.gem
+ }
+ c = `#{command}`
+ puts c
+ return c
+ end
+
+ it "should build" do
+ clean_test_gem.should be_true
+ install_gem.should be_true
+ remove_pkg.should be_true
+ end
+
+end
Oops, something went wrong.

0 comments on commit 8c5afe1

Please sign in to comment.