myshows 0.1.1 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
data.tar.gz.sig CHANGED
Binary file
data/Manifest CHANGED
@@ -1,7 +1,6 @@
1
1
  Manifest
2
2
  README.rdoc
3
3
  Rakefile
4
- all-api.rb
5
4
  lib/myshows.rb
6
5
  lib/myshows/api.rb
7
6
  lib/myshows/episode.rb
@@ -9,5 +8,7 @@ lib/myshows/item.rb
9
8
  lib/myshows/profile.rb
10
9
  lib/myshows/search.rb
11
10
  lib/myshows/show.rb
11
+ lib/myshows/title_matcher.rb
12
12
  myshows.gemspec
13
13
  spec/myshows_spec.rb
14
+ spec/title_matcher_spec.rb
@@ -11,6 +11,10 @@ And use
11
11
  profile = MyShows::Profile.new 'demo', 'fe01ce2a7fbac8fafaed7c982a04e229'
12
12
  profile.shows # => all user shows
13
13
 
14
+ # you can find show by title among user shows (smart search)
15
+ profile.show 'big bang theory' # => show "The Big Bang Theory"
16
+ profile.show 'TBBT' # => show "The Big Bang Theory"
17
+
14
18
  search = MyShows::Search.new
15
19
  tbbt = search.show("The Big Bang Theory").first
16
20
  tbbt.title # => "The Big Bang Theory"
@@ -18,6 +22,10 @@ And use
18
22
  # and many other fields provided by API
19
23
 
20
24
  tbbt.episodes # => [...] - all episodes
25
+
26
+ # you can find episode by title (smart search)
27
+ pilot = tbbt.episode "the pilot episode"
28
+ # or by season and episode number
21
29
  pilot = tbbt.episode 1, 1
22
30
  pilot.title # => "Pilot"
23
31
  pilot.show # => tbbt
data/Rakefile CHANGED
@@ -2,7 +2,7 @@ require 'rubygems'
2
2
  require 'rake'
3
3
  require 'echoe'
4
4
 
5
- Echoe.new('myshows', '0.1.1') do |p|
5
+ Echoe.new('myshows', '0.2.0') do |p|
6
6
  p.summary = "MyShows API"
7
7
  p.description = "Object-oriented wrapper over API of http://myshows.ru"
8
8
  p.url = "http://github.com/cypok/myshows"
@@ -1,4 +1,5 @@
1
1
  require 'myshows/api'
2
+ require 'myshows/title_matcher'
2
3
 
3
4
  module MyShows
4
5
  # Profile initialization is needed to gain access
@@ -18,5 +19,24 @@ module MyShows
18
19
  def shows
19
20
  @api.user_shows
20
21
  end
22
+
23
+ # Smart search of one of user shows by title
24
+ def show(title)
25
+ found = shows.values_at *matcher.match(title)
26
+ case found.count
27
+ when 0
28
+ raise MyShows::Error.new "show with title \"#{title}\" was not found"
29
+ when 1
30
+ found.first
31
+ else
32
+ raise MyShows::Error.new "ambiguous title \"#{title}\" corresponds to shows #{found.map {|s| %Q["#{s}"]} * ', '}"
33
+ end
34
+ end
35
+
36
+ protected
37
+
38
+ def matcher
39
+ @matcher ||= MyShows::TitleMatcher.new shows.map(&:title)
40
+ end
21
41
  end
22
42
  end
@@ -1,4 +1,5 @@
1
1
  require 'myshows/item'
2
+ require 'myshows/title_matcher'
2
3
 
3
4
  module MyShows
4
5
  # Provides such methods:
@@ -36,9 +37,39 @@ module MyShows
36
37
  @api.show_episodes self
37
38
  end
38
39
 
39
- # Returns episode by season and episode number
40
- def episode(season_number, episode_number)
41
- episodes.detect {|e| e.season_number == season_number && e.episode_number == episode_number }
40
+ # Returns episode by title (smart search) or by season and episode number
41
+ def episode(*args)
42
+ if args.first.is_a? String
43
+ episode_by_title *args
44
+ else
45
+ episode_by_numbers *args
46
+ end
47
+ end
48
+
49
+ protected
50
+
51
+ def episode_by_title(title)
52
+ found = episodes.values_at *matcher.match(title)
53
+ case found.count
54
+ when 0
55
+ raise MyShows::Error.new "episode with title \"#{title}\" was not found in show #{self}"
56
+ when 1
57
+ found.first
58
+ else
59
+ raise MyShows::Error.new "ambiguous title \"#{title}\" corresponds to episodes #{found.map {|s| %Q["#{s}"]} * ', '}"
60
+ end
61
+ end
62
+
63
+ def matcher
64
+ @matcher ||= MyShows::TitleMatcher.new episodes.map(&:title)
65
+ end
66
+
67
+ def episode_by_numbers(season_number, episode_number)
68
+ episodes.detect {|e| e.season_number == season_number && e.episode_number == episode_number }.tap do |e|
69
+ if e.nil?
70
+ raise MyShows::Error.new "episode with number #{season_number}x#{episode_number} was not found in show #{self}"
71
+ end
72
+ end
42
73
  end
43
74
  end
44
75
  end
@@ -0,0 +1,67 @@
1
+ module MyShows
2
+ class TitleMatcher
3
+ # You could extend this list
4
+ MATCHING_PROCS = [
5
+ # simple
6
+ proc {|src, title| src == title },
7
+
8
+ # flash forward => FlashForward
9
+ # lietome => Lie to Me
10
+ proc {|src, title| src.gsub(' ', '') == title.gsub(' ', '') },
11
+
12
+ # tbbt => The Big Bang Theory
13
+ proc {|src, title| src == title.split.map{|w| w[0,1]} * '' },
14
+
15
+ # avatar => Avatar: The Last Airbender
16
+ proc {|src, title| title.split.include? src },
17
+
18
+ # house m d => House
19
+ proc {|src, title| src.split.include? title },
20
+ ]
21
+
22
+ def initialize(titles)
23
+ @titles = titles.map {|s| strip(s)}
24
+ @titles_wo_articles = @titles.map {|t| wo_articles(t) }
25
+ end
26
+
27
+ # Tries to find title closest to src,
28
+ # returns list of indexes of titles
29
+ def match(src)
30
+ matched = []
31
+
32
+ src = strip(src)
33
+
34
+
35
+ MATCHING_PROCS.each do |matcher|
36
+ @titles.each_with_index do |title, i|
37
+ matched << i if matcher.call(src, title)
38
+ end
39
+ return matched unless matched.empty?
40
+ end
41
+
42
+ src_wo_articles = wo_articles(src)
43
+ MATCHING_PROCS.each do |matcher|
44
+ @titles_wo_articles.each_with_index do |title_wo_articles, i|
45
+ matched << i if matcher.call(src_wo_articles, title_wo_articles)
46
+ end
47
+ return matched unless matched.empty?
48
+ end
49
+
50
+ []
51
+ end
52
+
53
+ private
54
+
55
+ def strip(s)
56
+ s.clone.downcase.
57
+ gsub(/\(\d{4}\)/, ''). # to clean "V (2009)"
58
+ gsub(/\([A-Za-z]{2}\)/, ''). # to clean "Bless This House (US)"
59
+ gsub(/[^A-Za-z0-9]/, ' '). # to clean "Star Wars: the Clone Wars"
60
+ gsub(/ +/, ' ').strip # remove extra spaces
61
+ end
62
+
63
+ def wo_articles(str)
64
+ str.split.reject {|w| w =~ /^the|an?$/ } * ' '
65
+ end
66
+ end
67
+ end
@@ -2,16 +2,16 @@
2
2
 
3
3
  Gem::Specification.new do |s|
4
4
  s.name = %q{myshows}
5
- s.version = "0.1.1"
5
+ s.version = "0.2.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 = ["Vladimir Parfinenko"]
9
9
  s.cert_chain = ["/Users/cypok/.gem/gem-public_cert.pem"]
10
- s.date = %q{2011-01-26}
10
+ s.date = %q{2011-01-29}
11
11
  s.description = %q{Object-oriented wrapper over API of http://myshows.ru}
12
12
  s.email = %q{vladimir.parfinenko@gmail.com}
13
- s.extra_rdoc_files = ["README.rdoc", "lib/myshows.rb", "lib/myshows/api.rb", "lib/myshows/episode.rb", "lib/myshows/item.rb", "lib/myshows/profile.rb", "lib/myshows/search.rb", "lib/myshows/show.rb"]
14
- s.files = ["Manifest", "README.rdoc", "Rakefile", "lib/myshows.rb", "lib/myshows/api.rb", "lib/myshows/episode.rb", "lib/myshows/item.rb", "lib/myshows/profile.rb", "lib/myshows/search.rb", "lib/myshows/show.rb", "myshows.gemspec", "spec/myshows_spec.rb"]
13
+ s.extra_rdoc_files = ["README.rdoc", "lib/myshows.rb", "lib/myshows/api.rb", "lib/myshows/episode.rb", "lib/myshows/item.rb", "lib/myshows/profile.rb", "lib/myshows/search.rb", "lib/myshows/show.rb", "lib/myshows/title_matcher.rb"]
14
+ s.files = ["Manifest", "README.rdoc", "Rakefile", "lib/myshows.rb", "lib/myshows/api.rb", "lib/myshows/episode.rb", "lib/myshows/item.rb", "lib/myshows/profile.rb", "lib/myshows/search.rb", "lib/myshows/show.rb", "lib/myshows/title_matcher.rb", "myshows.gemspec", "spec/myshows_spec.rb", "spec/title_matcher_spec.rb"]
15
15
  s.homepage = %q{http://github.com/cypok/myshows}
16
16
  s.rdoc_options = ["--line-numbers", "--inline-source", "--title", "Myshows", "--main", "README.rdoc"]
17
17
  s.require_paths = ["lib"]
@@ -11,6 +11,24 @@ describe MyShows do
11
11
  it "should return user shows" do
12
12
  @profile.shows.map(&:title).should include TBBT
13
13
  end
14
+
15
+ describe "#show" do
16
+ it "should find user show by title" do
17
+ @profile.show('TBBT').title.should == TBBT
18
+ end
19
+
20
+ it "should raise exception if show was not found" do
21
+ lambda do
22
+ @profile.show('WTF?')
23
+ end.should raise_error MyShows::Error
24
+ end
25
+
26
+ it "should raise exception if title is ambiguous" do
27
+ lambda do
28
+ @profile.show('The')
29
+ end.should raise_error MyShows::Error
30
+ end
31
+ end
14
32
  end
15
33
 
16
34
  describe MyShows::Search do
@@ -42,10 +60,38 @@ describe MyShows do
42
60
  @show.episodes.should have_at_least(10).items
43
61
  end
44
62
 
45
- it "should find episode by season and episode number" do
46
- e = @show.episode(1, 2)
47
- e.season_number.should == 1
48
- e.episode_number.should == 2
63
+ describe "#episode" do
64
+
65
+ it "should find episode by season and episode number" do
66
+ e = @show.episode(1, 2)
67
+ e.season_number.should == 1
68
+ e.episode_number.should == 2
69
+ end
70
+
71
+ it "should find episode by title" do
72
+ e = @show.episode("pilot")
73
+ e.title.should == "Pilot"
74
+ e.season_number.should == 1
75
+ e.episode_number.should == 1
76
+ end
77
+
78
+ it "should raise exception if nothing was found" do
79
+ lambda do
80
+ @show.episode(99, 99)
81
+ end.should raise_error MyShows::Error
82
+ end
83
+
84
+ it "should raise exception if nothing was found" do
85
+ lambda do
86
+ @show.episode "Non existent episode"
87
+ end.should raise_error MyShows::Error
88
+ end
89
+
90
+ it "should raise exception if title is ambiguous" do
91
+ lambda do
92
+ @show.episode "The"
93
+ end.should raise_error MyShows::Error
94
+ end
49
95
  end
50
96
  end
51
97
 
@@ -0,0 +1,83 @@
1
+ require 'myshows'
2
+
3
+ describe MyShows::TitleMatcher do
4
+ before :all do
5
+ @titles = <<-END
6
+ V (2009)
7
+ Star Wars: The Clone Wars (2008)
8
+ Over There (US)
9
+ South Park
10
+ Lost
11
+ How I Met Your Mother
12
+ The IT Crowd
13
+ Due South (1994)
14
+ The Big Bang Theory
15
+ Life on Mars (UK)
16
+ Lie to Me
17
+ Avatar: The Last Airbender
18
+ FlashForward
19
+ Desperate Housewifes
20
+ END
21
+ @titles = @titles.split "\n"
22
+
23
+ @matcher = MyShows::TitleMatcher.new @titles
24
+ end
25
+
26
+ it "should find nothing" do
27
+ match("Unknown series").should be_empty
28
+ end
29
+
30
+ it "should simply find" do
31
+ match("Lost").should == ["Lost"]
32
+ end
33
+
34
+ it "should ingore year of series start" do
35
+ match("V").should == ["V (2009)"]
36
+ end
37
+
38
+ it "should ingore country of series creation" do
39
+ match("Over There").should == ["Over There (US)"]
40
+ end
41
+
42
+ it "should ignore all but letters" do
43
+ match("Star Wars The Clone Wars").should == ["Star Wars: The Clone Wars (2008)"]
44
+ end
45
+
46
+ it "should find ambiguous titles" do
47
+ match("South").should == ["South Park", "Due South (1994)"]
48
+ end
49
+
50
+ it "should find separeted title" do
51
+ match("Flash Forward").should == ["FlashForward"]
52
+ end
53
+
54
+ it "should find joined title" do
55
+ match("lietome").should == ["Lie to Me"]
56
+ end
57
+
58
+ it "should find some part of title in src" do
59
+ match("Avatar").should == ["Avatar: The Last Airbender"]
60
+ end
61
+
62
+ it "should find abbreviated title" do
63
+ match("TBBT").should == ["The Big Bang Theory"]
64
+ end
65
+
66
+ it "should find title with extra article" do
67
+ match("Life on a Mars").should == ["Life on Mars (UK)"]
68
+ end
69
+
70
+ it "should find title without article" do
71
+ match("IT Crowd").should == ["The IT Crowd"]
72
+ end
73
+
74
+ it "should find title with wrong article" do
75
+ match("An IT Crowd").should == ["The IT Crowd"]
76
+ end
77
+
78
+ protected
79
+
80
+ def match(src)
81
+ @titles.values_at *@matcher.match(src)
82
+ end
83
+ end
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: myshows
3
3
  version: !ruby/object:Gem::Version
4
- hash: 25
4
+ hash: 23
5
5
  prerelease:
6
6
  segments:
7
7
  - 0
8
- - 1
9
- - 1
10
- version: 0.1.1
8
+ - 2
9
+ - 0
10
+ version: 0.2.0
11
11
  platform: ruby
12
12
  authors:
13
13
  - Vladimir Parfinenko
@@ -36,7 +36,7 @@ cert_chain:
36
36
  78F0qvtLjR0DAnN6uYs98PR+jHE+0ckLX3D9sw==
37
37
  -----END CERTIFICATE-----
38
38
 
39
- date: 2011-01-26 00:00:00 +06:00
39
+ date: 2011-01-29 00:00:00 +06:00
40
40
  default_executable:
41
41
  dependencies:
42
42
  - !ruby/object:Gem::Dependency
@@ -110,6 +110,7 @@ extra_rdoc_files:
110
110
  - lib/myshows/profile.rb
111
111
  - lib/myshows/search.rb
112
112
  - lib/myshows/show.rb
113
+ - lib/myshows/title_matcher.rb
113
114
  files:
114
115
  - Manifest
115
116
  - README.rdoc
@@ -121,8 +122,10 @@ files:
121
122
  - lib/myshows/profile.rb
122
123
  - lib/myshows/search.rb
123
124
  - lib/myshows/show.rb
125
+ - lib/myshows/title_matcher.rb
124
126
  - myshows.gemspec
125
127
  - spec/myshows_spec.rb
128
+ - spec/title_matcher_spec.rb
126
129
  has_rdoc: true
127
130
  homepage: http://github.com/cypok/myshows
128
131
  licenses: []
metadata.gz.sig CHANGED
Binary file