splattael-shoutcast_api 0.0.2 → 0.1.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.
data/Manifest CHANGED
@@ -1,4 +1,6 @@
1
1
  Rakefile
2
+ bin/shoutcast_search
3
+ lib/delegator.rb
2
4
  lib/shoutcast_api.rb
3
5
  README.rdoc
4
6
  Manifest
@@ -9,4 +11,5 @@ test/fixtures/genrelist.plain
9
11
  test/fixtures/search_death.plain
10
12
  test/fixtures/empty.plain
11
13
  test/test_basic.rb
14
+ test/test_delegator.rb
12
15
  shoutcast_api.gemspec
data/README.rdoc CHANGED
@@ -8,7 +8,7 @@ Uses httparty and roxml for fetch and parsing data from http://yp.shoutcast.com/
8
8
  require 'shoutcast_api'
9
9
 
10
10
  # Stations
11
- Shoutcast.search(:name => "Chronix").stations.each do |station|
11
+ Shoutcast.search(:name => "Chronix").each do |station|
12
12
  p station
13
13
  puts station.tunein
14
14
  end
@@ -17,7 +17,6 @@ Uses httparty and roxml for fetch and parsing data from http://yp.shoutcast.com/
17
17
 
18
18
  # Genres
19
19
  Shoutcast.genres # => all genres
20
- Shoutcast.genres /op/ # => genres which match "op"
21
20
 
22
21
  == Command line
23
22
 
@@ -28,7 +27,5 @@ Uses httparty and roxml for fetch and parsing data from http://yp.shoutcast.com/
28
27
 
29
28
  == TODO
30
29
 
31
- * Tests!
32
30
  * Docs!
33
- * command line options transformations
34
- * handle empty responses like search(:search => "")
31
+ * command line options transformations
data/Rakefile CHANGED
@@ -6,12 +6,23 @@ desc 'Default: run unit tests.'
6
6
  task :default => :test
7
7
 
8
8
  require 'echoe'
9
-
10
9
  Echoe.new('shoutcast_api') do |gem|
11
- gem.version = '0.0.2'
10
+ gem.version = '0.1.0'
12
11
  gem.author = 'Peter Suschlik'
13
12
  gem.summary = 'Simple Shoutcast.com API.'
14
13
  gem.email = 'peter-scapi@suschlik.de'
15
14
  gem.url = %q{http://github.com/splattael/shoutcast_api}
16
15
  gem.runtime_dependencies = [ "httparty ~>0.4", "roxml ~>2.5" ]
16
+ gem.ignore_pattern = ["tags"]
17
+ end
18
+
19
+ desc "Tag files for vim"
20
+ task :ctags do
21
+ dirs = $LOAD_PATH.select {|path| File.directory?(path) }
22
+ system "ctags -R #{dirs.join(" ")}"
23
+ end
24
+
25
+ desc "Find whitespace at line ends"
26
+ task :eol do
27
+ system "grep -nrE ' +$' *"
17
28
  end
@@ -0,0 +1,26 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'rubygems'
4
+
5
+ require 'shoutcast_api'
6
+
7
+ if ARGV.size > 0
8
+ options = ARGV.inject({}) do |hash, arg|
9
+ key, value = arg.split(/=/)
10
+ hash[key.intern] = value
11
+ hash
12
+ end
13
+ # TODO do more transformations
14
+ # br -> bitrate
15
+ # ct -> current_title
16
+ # can ROXML help us?
17
+ options[:search] = options.delete(:name) if options[:name]
18
+
19
+ puts Shoutcast::Station.header
20
+ Shoutcast.search(options).sort.reverse.each do |station|
21
+ puts station
22
+ end
23
+ else
24
+ puts "Genres: ", Shoutcast.genres.map { |g| g.name }.join(", ")
25
+ end
26
+
data/lib/delegator.rb ADDED
@@ -0,0 +1,36 @@
1
+ module Shoutcast
2
+
3
+ # Delegates methods via Forwardable.
4
+ module Delegator
5
+ def self.included(base)
6
+ base.extend ClassMethods
7
+ end
8
+
9
+ module ClassMethods
10
+ # Delegates all methods defined +klass+ to +object+.
11
+ #
12
+ # === Usage
13
+ # class ArrayMimic < SomeInheritance
14
+ #
15
+ # delegate_all :@array, Array
16
+ #
17
+ # end
18
+ #
19
+ # array = ArrayMimic.new
20
+ # array.push 1, 2, 3
21
+ # array.each do |item|
22
+ # p item
23
+ # end
24
+ #
25
+ def delegate_all(object, klass)
26
+ class_eval <<-EVAL
27
+ extend Forwardable
28
+
29
+ def_delegators :#{object}, *(#{klass}.instance_methods - instance_methods)
30
+ EVAL
31
+ end
32
+ end
33
+
34
+ end
35
+
36
+ end
data/lib/shoutcast_api.rb CHANGED
@@ -2,46 +2,58 @@ require 'httparty'
2
2
  require 'roxml'
3
3
  require 'forwardable'
4
4
 
5
+ require 'delegator'
6
+
5
7
  module Shoutcast
6
8
  extend Forwardable
7
9
  extend self
8
10
 
9
- def_delegators :Fetcher, :genre, :search
11
+ def_delegators :Fetcher, :genres, :search
10
12
 
11
13
  class Fetcher
12
14
  include HTTParty
13
- base_uri 'http://yp.shoutcast.com/sbin/newxml.phtml'
15
+ base_uri "http://yp.shoutcast.com"
14
16
  format :plain
15
17
 
16
- def self.genres(filter=nil)
17
- list = Genrelist.from_xml fetch
18
-
19
- list.filter(filter)
18
+ def self.genres
19
+ fetch do |xml|
20
+ Genrelist.from_xml xml
21
+ end
20
22
  end
21
23
 
22
24
  def self.search(options={})
23
- Stationlist.from_xml fetch(options)
25
+ fetch(options) do |xml|
26
+ Stationlist.from_xml xml
27
+ end
24
28
  end
25
29
 
26
30
  private
27
31
 
28
- def self.fetch(options={})
29
- options.update(:nocache => Time.now.to_f)
30
- get('', :query => options).body
32
+ def self.fetch(options={}, &block)
33
+ options.update(:nocache => Time.now.to_f) if options
34
+ data = get("/sbin/newxml.phtml", :query => options).body
35
+
36
+ block.call(data) unless data.empty?
31
37
  end
32
38
  end
33
39
 
34
40
  # XML
35
41
 
36
- class Base
37
- include ROXML
42
+ module Xml
43
+ def self.included(base)
44
+ base.send(:include, ROXML)
45
+ base.extend ClassMethods
46
+ end
38
47
 
39
- def self.trim
40
- proc { |v| v.to_s.strip }
48
+ module ClassMethods
49
+ def trim
50
+ proc { |v| v.to_s.strip.squeeze(" ") }
51
+ end
41
52
  end
42
53
  end
43
54
 
44
- class Station < Base
55
+ class Station
56
+ include Xml
45
57
  # <station
46
58
  # id="423873"
47
59
  # name="www.deathmetal.at"
@@ -79,26 +91,36 @@ module Shoutcast
79
91
  end
80
92
  end
81
93
 
82
- class Stationlist < Base
94
+ class Stationlist
95
+ include Xml
96
+ include Delegator
97
+
98
+ delegate_all :@stations, Array
99
+
83
100
  # <tunein base="/sbin/tunein-station.pls"/>
84
101
  # <station... /> <station .../>
85
- BASE_URL = "http://yp.shoutcast.com"
86
102
 
87
103
  xml_reader :tunein_base_path, :from => '@base', :in => 'tunein'
88
- xml_reader :stations, :as => [ Station ]
104
+ xml_attr :stations, :as => [ Station ]
105
+
106
+ class << self
107
+ attr_accessor :base_uri
108
+ end
109
+ self.base_uri = Fetcher.base_uri
89
110
 
90
111
  def tunein(station)
91
- "#{BASE_URL}#{tunein_base_path}?id=#{station.id}"
112
+ "#{self.class.base_uri}#{tunein_base_path}?id=#{station.id}"
92
113
  end
93
114
 
94
115
  private
95
116
 
96
117
  def after_parse
97
- stations.each { |station| station.tunein = tunein(station) }
118
+ each { |station| station.tunein = tunein(station) }
98
119
  end
99
120
  end
100
121
 
101
- class Genre < Base
122
+ class Genre
123
+ include Xml
102
124
  # <genre name="24h"/>
103
125
  xml_reader :name, :from => :attr
104
126
 
@@ -107,44 +129,14 @@ module Shoutcast
107
129
  end
108
130
  end
109
131
 
110
- class Genrelist < Base
111
- xml_reader :genres, :as => [ Genre ]
112
-
113
- def filter(option=nil)
114
- case option
115
- when String
116
- genres.select { |genre| genre.name == option }
117
- when Regexp
118
- genres.select { |genre| genre.name =~ option }
119
- else
120
- genres
121
- end
122
- end
123
- end
132
+ class Genrelist
133
+ include Xml
134
+ include Delegator
124
135
 
125
- end
136
+ delegate_all :@genres, Array
126
137
 
127
- if $0 == __FILE__
128
- require 'pp'
138
+ xml_attr :genres, :as => [ Genre ]
129
139
 
130
- if ARGV.size > 0
131
- options = ARGV.inject({}) do |hash, arg|
132
- key, value = arg.split(/=/)
133
- hash[key.intern] = value
134
- hash
135
- end
136
- # TODO do more transformations
137
- # br -> bitrate
138
- # ct -> current_title
139
- # can ROXML help us?
140
- options[:search] = options.delete(:name) if options[:name]
141
-
142
- puts Shoutcast::Station.header
143
- Shoutcast.search(options).stations.sort.reverse.each do |station|
144
- puts station
145
- end
146
- else
147
- pp Shoutcast.genres
148
140
  end
149
141
 
150
142
  end
@@ -2,15 +2,17 @@
2
2
 
3
3
  Gem::Specification.new do |s|
4
4
  s.name = %q{shoutcast_api}
5
- s.version = "0.0.2"
5
+ s.version = "0.1.0"
6
6
 
7
7
  s.required_rubygems_version = Gem::Requirement.new(">= 1.2") if s.respond_to? :required_rubygems_version=
8
8
  s.authors = ["Peter Suschlik"]
9
9
  s.date = %q{2009-05-14}
10
+ s.default_executable = %q{shoutcast_search}
10
11
  s.description = %q{Simple Shoutcast.com API.}
11
12
  s.email = %q{peter-scapi@suschlik.de}
12
- s.extra_rdoc_files = ["lib/shoutcast_api.rb", "README.rdoc"]
13
- s.files = ["Rakefile", "lib/shoutcast_api.rb", "README.rdoc", "Manifest", "test/test_xml.rb", "test/helper.rb", "test/test_fetcher.rb", "test/fixtures/genrelist.plain", "test/fixtures/search_death.plain", "test/fixtures/empty.plain", "test/test_basic.rb", "shoutcast_api.gemspec"]
13
+ s.executables = ["shoutcast_search"]
14
+ s.extra_rdoc_files = ["bin/shoutcast_search", "lib/delegator.rb", "lib/shoutcast_api.rb", "README.rdoc"]
15
+ s.files = ["Rakefile", "bin/shoutcast_search", "lib/delegator.rb", "lib/shoutcast_api.rb", "README.rdoc", "Manifest", "test/test_xml.rb", "test/helper.rb", "test/test_fetcher.rb", "test/fixtures/genrelist.plain", "test/fixtures/search_death.plain", "test/fixtures/empty.plain", "test/test_basic.rb", "test/test_delegator.rb", "shoutcast_api.gemspec"]
14
16
  s.has_rdoc = true
15
17
  s.homepage = %q{http://github.com/splattael/shoutcast_api}
16
18
  s.rdoc_options = ["--line-numbers", "--inline-source", "--title", "Shoutcast_api", "--main", "README.rdoc"]
@@ -18,7 +20,7 @@ Gem::Specification.new do |s|
18
20
  s.rubyforge_project = %q{shoutcast_api}
19
21
  s.rubygems_version = %q{1.3.1}
20
22
  s.summary = %q{Simple Shoutcast.com API.}
21
- s.test_files = ["test/test_xml.rb", "test/test_fetcher.rb", "test/test_basic.rb"]
23
+ s.test_files = ["test/test_xml.rb", "test/test_fetcher.rb", "test/test_basic.rb", "test/test_delegator.rb"]
22
24
 
23
25
  if s.respond_to? :specification_version then
24
26
  current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
data/test/test_basic.rb CHANGED
@@ -1,5 +1,14 @@
1
1
  require File.join(File.dirname(__FILE__), 'helper')
2
2
 
3
+ class ShoutcastTest < Test::Unit::TestCase
4
+
5
+ def test_delegators
6
+ assert_respond_to Shoutcast, :genres
7
+ assert_respond_to Shoutcast, :search
8
+ end
9
+
10
+ end
11
+
3
12
  class ExtensionsTest < Test::Unit::TestCase
4
13
 
5
14
  def test_file_fixture
@@ -0,0 +1,27 @@
1
+ require File.join(File.dirname(__FILE__), 'helper')
2
+
3
+ class ArrayMimic
4
+ include Shoutcast::Delegator
5
+
6
+ delegate_all :@array, Array
7
+
8
+ def initialize
9
+ @array = []
10
+ end
11
+
12
+ end
13
+
14
+ class DelegatorTest < Test::Unit::TestCase
15
+
16
+ def test_method_delegation
17
+ ary = ArrayMimic.new
18
+ ary.push 1, 2, 3
19
+
20
+ assert_equal 3, ary.size
21
+ assert_equal 1, ary.first
22
+ assert_equal 3, ary.last
23
+ assert_respond_to ary, :each
24
+ assert_equal [].methods.sort, ary.methods.sort
25
+ end
26
+
27
+ end
data/test/test_fetcher.rb CHANGED
@@ -1,3 +1,41 @@
1
1
  require File.join(File.dirname(__FILE__), 'helper')
2
2
 
3
- # TODO integeration tests with fetcher.
3
+ class FetcherTest < Test::Unit::TestCase
4
+ include Shoutcast
5
+
6
+ def test_base_uri
7
+ assert_equal "http://yp.shoutcast.com", Stationlist.base_uri
8
+ end
9
+
10
+ def test_genres_list
11
+ stub_http_response_with("genrelist.plain")
12
+
13
+ list = Fetcher.genres
14
+ # DRY test/text_xml.rb GenrelistTest
15
+ assert_instance_of Genrelist, list
16
+ assert_instance_of Genre, list.first
17
+ end
18
+
19
+ def test_genres_empty_response
20
+ stub_http_response_with("empty.plain")
21
+
22
+ assert_nil Fetcher.genres
23
+ end
24
+
25
+ def test_search_with_invalid_option
26
+ stub_http_response_with("search_death.plain")
27
+
28
+ list = Fetcher.search
29
+ # DRY test/text_xml.rb StationlistTest
30
+ assert_instance_of Stationlist, list
31
+ assert_equal "/sbin/tunein-station.pls", list.tunein_base_path
32
+ assert_instance_of Station, list.first
33
+ end
34
+
35
+ def test_search_empty_response
36
+ stub_http_response_with("empty.plain")
37
+
38
+ assert_nil Fetcher.genres
39
+ end
40
+
41
+ end
data/test/test_xml.rb CHANGED
@@ -64,6 +64,7 @@ class StationTest < Test::Unit::TestCase
64
64
 
65
65
  end
66
66
 
67
+
67
68
  class StationlistTest < Test::Unit::TestCase
68
69
  include Shoutcast
69
70
 
@@ -74,19 +75,22 @@ class StationlistTest < Test::Unit::TestCase
74
75
  def test_attributes
75
76
  assert_instance_of Stationlist, @list
76
77
  assert_equal "/sbin/tunein-station.pls", @list.tunein_base_path
77
- assert_instance_of Array, @list.stations
78
- assert_equal 49, @list.stations.size
79
- assert_instance_of Station, @list.stations.first
78
+ assert_equal 49, @list.size
79
+ assert_instance_of Station, @list.first
80
+ end
81
+
82
+ def test_base_uri
83
+ assert_equal "http://yp.shoutcast.com", Stationlist.base_uri
80
84
  end
81
85
 
82
86
  def test_tunein
83
- station = @list.stations.first
87
+ station = @list.first
84
88
 
85
89
  assert_equal "http://yp.shoutcast.com/sbin/tunein-station.pls?id=#{station.id}", @list.tunein(station)
86
90
  end
87
91
 
88
92
  def test_tunein_propagtion_after_parse
89
- station = @list.stations.first
93
+ station = @list.first
90
94
 
91
95
  assert_equal @list.tunein(station), station.tunein
92
96
  end
@@ -101,28 +105,35 @@ class GenrelistTest < Test::Unit::TestCase
101
105
  @list = Genrelist.from_xml file_fixture("genrelist.plain")
102
106
  end
103
107
 
104
- def test_parsing
108
+ def test_array_mimic
105
109
  assert_instance_of Genrelist, @list
106
- assert_instance_of Array, @list.genres
107
- assert_equal 434, @list.genres.size
108
- assert_instance_of Genre, @list.genres.first
109
- end
110
-
111
- def test_filter
112
- assert_equal @list.genres, @list.filter
113
-
114
- assert_equal 1, @list.filter("Rock").size
115
- assert_equal "Rock", @list.filter("Rock").first.name
116
-
117
- assert_equal 13, @list.filter(/op/).size
118
- assert_equal "Autopilot", @list.filter(/op/).first.name
110
+ assert_equal 434, @list.size
111
+ assert_instance_of Genre, @list.first
112
+ assert_respond_to @list, :each
113
+ assert_raise(NoMethodError) { @list.nothing_found }
119
114
  end
120
115
 
121
116
  def test_genre_name
122
- sorted = @list.genres.sort
117
+ sorted = @list.sort
123
118
 
124
119
  assert_equal "24h", sorted.first.name
125
120
  assert_equal "Zouk", sorted.last.name
126
121
  end
127
122
 
128
123
  end
124
+
125
+
126
+ class MyClass
127
+ include Shoutcast::Xml
128
+ end
129
+
130
+ class XmlTest < Test::Unit::TestCase
131
+
132
+ def test_trim
133
+ assert_respond_to MyClass, :trim
134
+
135
+ string = " test mee "
136
+ assert_equal "test mee", MyClass.trim.call(string)
137
+ end
138
+
139
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: splattael-shoutcast_api
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.2
4
+ version: 0.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Peter Suschlik
@@ -10,7 +10,7 @@ bindir: bin
10
10
  cert_chain: []
11
11
 
12
12
  date: 2009-05-14 00:00:00 -07:00
13
- default_executable:
13
+ default_executable: shoutcast_search
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: httparty
@@ -34,15 +34,19 @@ dependencies:
34
34
  version:
35
35
  description: Simple Shoutcast.com API.
36
36
  email: peter-scapi@suschlik.de
37
- executables: []
38
-
37
+ executables:
38
+ - shoutcast_search
39
39
  extensions: []
40
40
 
41
41
  extra_rdoc_files:
42
+ - bin/shoutcast_search
43
+ - lib/delegator.rb
42
44
  - lib/shoutcast_api.rb
43
45
  - README.rdoc
44
46
  files:
45
47
  - Rakefile
48
+ - bin/shoutcast_search
49
+ - lib/delegator.rb
46
50
  - lib/shoutcast_api.rb
47
51
  - README.rdoc
48
52
  - Manifest
@@ -53,6 +57,7 @@ files:
53
57
  - test/fixtures/search_death.plain
54
58
  - test/fixtures/empty.plain
55
59
  - test/test_basic.rb
60
+ - test/test_delegator.rb
56
61
  - shoutcast_api.gemspec
57
62
  has_rdoc: true
58
63
  homepage: http://github.com/splattael/shoutcast_api
@@ -89,3 +94,4 @@ test_files:
89
94
  - test/test_xml.rb
90
95
  - test/test_fetcher.rb
91
96
  - test/test_basic.rb
97
+ - test/test_delegator.rb