kat 0.3.0 → 1.0.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.
Files changed (7) hide show
  1. checksums.yaml +4 -4
  2. data/bin/kat +127 -0
  3. data/kat.gemspec +4 -4
  4. data/lib/kat.rb +91 -35
  5. data/lib/kat/version.rb +3 -1
  6. data/test/kat_test.rb +76 -210
  7. metadata +38 -8
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 6431728ef307439d3dff0b3f60e3619c0ae4d37c
4
- data.tar.gz: 914cef06e731347f85c4c8ba9c5363711d134e4a
3
+ metadata.gz: a6ad7f5809e7cfbdc5379f566d93c61a361a51e6
4
+ data.tar.gz: 852186a99d1af3374c4de52f0bb91c45d3c3a5bc
5
5
  SHA512:
6
- metadata.gz: d64ef6998d9d27411680c8aa08e42d6cf5d15dbe33a82122a9ede9ba04c75841e24a93b98c126207beadd3713e4d7102c67ccbd5fdd0411b716011050ed33030
7
- data.tar.gz: 7ec114ce7cf00ca98b9d94345c8cc1b6dbaf3aaf812334146fe58ae7e84f224cb92ec677c3e948d4593939e17d4058d3c4c11b967a75317fac8baa133668aa56
6
+ metadata.gz: cd2896742673ed05ccec2bd1ec63b2af9498911683a9b21e8ad0a7352d8311a2532f7ef8a26960266e4514d9a5aae979762acd710fde36b252159c74cb41d301
7
+ data.tar.gz: fc2812d838cc89f103fa9a52e6f2a3ae1345f466d9a732539eb1d26bc6adfa0971ff76961cd7296606aff6b83af9d8fa47639f34b66b2cb17a21905a9477b1a2
data/bin/kat ADDED
@@ -0,0 +1,127 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ e = []
4
+
5
+ require 'open-uri'
6
+ %w(kat trollop highline).sort.each do |lib|
7
+ begin
8
+ require lib
9
+ rescue LoadError
10
+ e << lib.sub(/_/, '')
11
+ end
12
+ end
13
+
14
+ unless e.empty?
15
+ puts <<-EOS
16
+ Kickass Torrents Search relies on #{e.join(', ').sub(/^(.*), /, '\1 and ')}. To download the gem#{'s' if e.size > 1} type:
17
+
18
+ gem install #{e.join ' '}
19
+
20
+ EOS
21
+ exit
22
+ end
23
+
24
+ VERSION_STR = "#{Kat::NAME} #{Kat::VERSION} (c) 2013 #{Kat::AUTHOR}"
25
+
26
+ list_args = { :categories => :category, :times => :added,
27
+ :languages => :language, :platforms => :platform }
28
+
29
+ options = Trollop::options do
30
+ version VERSION_STR
31
+ banner <<-EOS
32
+ #{VERSION_STR}
33
+
34
+ Usage: #{File.basename __FILE__} [options] <query>+
35
+
36
+ Options:
37
+ EOS
38
+
39
+ opt :exact, 'Exact phrase', :type => :string
40
+ opt :or, 'Optional words', :type => :string, :multi => true
41
+ opt :without, 'Without this word', :type => :string, :multi => true
42
+
43
+ opt :sort, 'Sort field (size, files, time_add, seeders, leechers)', :type => :string
44
+ opt :asc, 'Ascending sort order (descending is default)', :type => :boolean
45
+
46
+ opt :added, 'Age of the torrent', :type => :string, :short => :a
47
+ opt :category, 'Category', :type => :string, :short => :c
48
+ opt :files, 'Number of files', :type => :int
49
+ opt :imdb, 'IMDB ID', :type => :int
50
+ opt :seeds, 'Minimum number of seeders', :type => :int, :short => :s
51
+ opt :user, 'Uploader', :type => :string
52
+ opt :season, 'Television season', :type => :int
53
+ opt :episode, 'Television episode', :type => :int, :short => :e
54
+
55
+ opt :language, 'Language', :type => :int
56
+ opt :platform, 'Game platform', :type => :int
57
+
58
+ opt :safe, 'Family safety filter', :type => :boolean
59
+ opt :verified, 'Verified', :type => :boolean, :short => :m
60
+
61
+ opt :output, 'Directory to save torrents in', :type => :string, :short => :o
62
+
63
+ list_args.each {|k, v| opt k, "List the #{k} that may be used with --#{v}", :type => :boolean }
64
+ end
65
+
66
+ unless list_args.select! {|k, v| options[k] }.empty?
67
+ puts VERSION_STR
68
+ list_args.each do |opt, label|
69
+ args = Kat.send opt
70
+ puts "\n #{label.to_s.capitalize}"
71
+ puts unless args.values.first.is_a? Array
72
+ args.each {|k, v| puts v.is_a?(Array) ? "\n %12s => #{v.join "\n\t\t "}" % k : " %-23s => #{v}" % k }
73
+ puts
74
+ end
75
+ else
76
+ k = Kat.new ARGV.join(' '), options
77
+ h = HighLine.new
78
+ page = 0
79
+ puts VERSION_STR
80
+
81
+ loop do
82
+ r = k.search page
83
+ if r.nil?
84
+ puts "\nNo results"
85
+ break
86
+ end
87
+
88
+ n = page < k.pages - 1
89
+ p = page > 0
90
+
91
+ puts "\n%-72s S L\n\n" % "Page #{page + 1} of #{k.pages}"
92
+ r.each_with_index do |t, i|
93
+ puts "%2d. %-64s %5d %5d" % [ i + 1, t[:title][0..63], t[:seeds], t[:leeches] ]
94
+ end
95
+
96
+ commands = "[#{'n' if n}#{'p' if p}q]|"
97
+ _01to09 = "[1#{r.size > 9 ? '-9' : '-' + r.size.to_s}]"
98
+ _10to19 = "#{r.size > 9 ? '|1[0-' + (r.size > 19 ? '9' : (r.size - 10).to_s) + ']' : ''}"
99
+ _20to25 = "#{r.size > 19 ? '|2[0-' + (r.size - 20).to_s + ']' : ''}"
100
+ prompt = "\n1#{r.size > 1 ? '-' + r.size.to_s : ''} to download" +
101
+ "#{', (n)ext' if n}" +
102
+ "#{', (p)rev' if p}" +
103
+ ', (q)uit: '
104
+
105
+ case (answer = h.ask(prompt) {|q| q.validate = /^(#{commands}#{_01to09}#{_10to19}#{_20to25})$/ })
106
+ when 'q' then break
107
+ when 'n' then page += 1 if n
108
+ when 'p' then page -= 1 if p
109
+ else
110
+ if (1..r.size).include? answer.to_i
111
+ torrent = k.results[page][answer.to_i - 1]
112
+ puts "\nDownloading: #{torrent[:title]}"
113
+
114
+ begin
115
+ uri = URI torrent[:download]
116
+ uri.query = nil
117
+ response = uri.read
118
+ file = "#{File.expand_path(options[:output] || '.')}/#{torrent[:title].gsub(/ /, '.').gsub(/[^a-z0-9()_.-]/i, '')}.torrent"
119
+ File.open(file, 'w') {|f| f.write response }
120
+ rescue => e
121
+ puts e.message
122
+ end
123
+ end
124
+ end
125
+ end
126
+ puts
127
+ end
@@ -6,14 +6,12 @@ require 'kat/version'
6
6
  Gem::Specification.new do |s|
7
7
  s.name = 'kat'
8
8
  s.version = Kat::VERSION
9
- s.date = '2013-08-09'
9
+ s.date = Time.new.strftime '%Y-%m-%d'
10
10
  s.author = 'Fission Xuiptz'
11
11
  s.email = 'fissionxuiptz@softwaremojo.com'
12
12
  s.homepage = 'http://github.com/fissionxuiptz/kat'
13
13
  s.license = 'MIT'
14
14
 
15
- s.rubyforge_project = 'kat'
16
-
17
15
  s.summary = 'Kickass Torrents Interface'
18
16
  s.description = 'A Ruby interface to Kickass Torrents'
19
17
 
@@ -22,5 +20,7 @@ Gem::Specification.new do |s|
22
20
  s.test_files = s.files.grep(%r{^(test|spec|features)/})
23
21
  s.require_paths = [ 'lib' ]
24
22
 
25
- s.add_runtime_dependency 'nokogiri'
23
+ s.add_runtime_dependency 'nokogiri', '~> 1.6'
24
+ s.add_runtime_dependency 'highline', '~> 1.6'
25
+ s.add_runtime_dependency 'trollop', '~> 2.0'
26
26
  end
data/lib/kat.rb CHANGED
@@ -1,22 +1,24 @@
1
- # TODO: Lookup advanced search for language and platform values
2
-
3
1
  require 'nokogiri'
4
2
  require 'open-uri'
3
+ require 'kat/version'
5
4
 
6
5
  class Kat
7
6
  KAT_URL = 'http://kickass.to'
8
- EMPTY_URL = "new"
9
- SEARCH_URL = "usearch"
7
+ EMPTY_URL = 'new'
8
+ SEARCH_URL = 'usearch'
10
9
  ADVANCED_URL = "#{KAT_URL}/torrents/search/advanced/"
11
10
 
12
- STRING_FIELDS = [ :category, :seeds, :user, :age, :files, :imdb, :season, :episode ]
13
-
14
- # The names of these fields are transposed for ease of use
15
- SELECT_FIELDS = [ { :name => :language, :id => :lang_id }, { :name => :platform, :id => :platform_id } ]
11
+ STRING_FIELDS = [ :seeds, :user, :files, :imdb, :season, :episode ]
16
12
 
17
13
  # If these are set to anything but nil or false, they're turned on in the query
18
14
  SWITCH_FIELDS = [ :safe, :verified ]
19
15
 
16
+ # The names of these fields are transposed for ease of use
17
+ SELECT_FIELDS = [ { :name => :categories, :label => :category, :id => :category },
18
+ { :name => :times, :label => :added, :id => :age },
19
+ { :name => :languages, :label => :language, :id => :lang_id },
20
+ { :name => :platforms, :label => :platform, :id => :platform_id } ]
21
+
20
22
  SORT_FIELDS = %w(size files_count time_add seeders leechers)
21
23
 
22
24
  # The number of pages of results
@@ -25,21 +27,23 @@ class Kat
25
27
  # Any error in searching is stored here
26
28
  attr_reader :error
27
29
 
30
+ @@doc = nil
31
+
28
32
  #
29
33
  # Create a new +Kat+ object to search Kickass Torrents.
30
- #
31
- # The search term can be nil, a string/symbol, or an array of strings/symbols.
32
- #
33
- # Valid options are in STRING_FIELDS, SELECT_FIELDS or SWITCH_FIELDS
34
+ # The search_term can be nil, a string/symbol, or an array of strings/symbols.
35
+ # Valid options are in STRING_FIELDS, SELECT_FIELDS or SWITCH_FIELDS.
34
36
  #
35
37
  def initialize search_term = nil, opts = {}
36
38
  @search_term = []
37
- @options = opts.is_a?(Hash) ? opts : {}
38
- self.query = search_term.is_a?(Array) ? search_term.dup : search_term
39
+ @options = {}
40
+
41
+ self.query = search_term
42
+ self.options = opts
39
43
  end
40
44
 
41
45
  #
42
- # Use Kat.search(search_term) to do a quick search
46
+ # Kat.search will do a quick search and return the results
43
47
  #
44
48
  def self.search search_term
45
49
  self.new(search_term).search
@@ -48,21 +52,20 @@ class Kat
48
52
  #
49
53
  # Generate a query string from the stored options, supplying an optional page number
50
54
  #
51
- def query page = 0
52
- q = [ SEARCH_URL, @query.join(' ').gsub(/[^a-z0-9: _-]/i, '') ]
53
- q = [ EMPTY_URL ] if q[1].empty?
54
- q << page + 1 if page > 0
55
- q << if SORT_FIELDS.include? @options[:sort].to_s
55
+ def query_str page = 0
56
+ str = [ SEARCH_URL, @query.join(' ').gsub(/[^a-z0-9: _-]/i, '') ]
57
+ str = [ EMPTY_URL ] if str[1].empty?
58
+ str << page + 1 if page > 0
59
+ str << if SORT_FIELDS.include? @options[:sort].to_s
56
60
  "?field=#{options[:sort].to_s}&sorder=#{options[:asc] ? 'asc' : 'desc'}"
57
61
  else
58
62
  '' # ensure a trailing slash after the search terms or page number
59
63
  end
60
- q.join '/'
64
+ str.join '/'
61
65
  end
62
66
 
63
67
  #
64
- # Change the search term for the query, triggering a rebuild of the query string
65
- # and clearing past results.
68
+ # Change the search term, triggering a query rebuild and clearing past results.
66
69
  #
67
70
  # Raises ArgumentError if search_term is not a String, Symbol or Array
68
71
  #
@@ -84,7 +87,7 @@ class Kat
84
87
  end
85
88
 
86
89
  #
87
- # Change search options with a hash, triggering a rebuild of the query string and
90
+ # Change search options with a hash, triggering a query string rebuild and
88
91
  # clearing past results.
89
92
  #
90
93
  # Raises ArgumentError if opts is not a Hash
@@ -101,9 +104,9 @@ class Kat
101
104
  # cache results for subsequent calls of search with the same query string.
102
105
  #
103
106
  def search page = 0
104
- unless query.empty? or @results[page] or (@pages > -1 and page >= @pages)
107
+ unless @results[page] or (@pages > -1 and page >= @pages)
105
108
  begin
106
- doc = Nokogiri::HTML(open("#{KAT_URL}/#{URI::encode(query page)}"))
109
+ doc = Nokogiri::HTML(open("#{KAT_URL}/#{URI::encode(query_str page)}"))
107
110
  @results[page] = doc.css('td.torrentnameCell').map do |node|
108
111
  { :title => node.css('a.normalgrey').text,
109
112
  :magnet => node.css('a.imagnet').first.attributes['href'].value,
@@ -128,13 +131,21 @@ class Kat
128
131
  rescue => e
129
132
  # No result throws a 404 error.
130
133
  @pages = 0 if e.class == OpenURI::HTTPError and e.message['404 Not Found']
131
- @error = { :error => e, :query => query(page) }
134
+ @error = { :error => e, :query => query_str(page) }
132
135
  end
133
136
  end
134
137
 
135
138
  results[page]
136
139
  end
137
140
 
141
+ #
142
+ # For message chaining
143
+ #
144
+ def do_search page = 0
145
+ search page
146
+ self
147
+ end
148
+
138
149
  #
139
150
  # Get a copy of the results
140
151
  #
@@ -143,7 +154,14 @@ class Kat
143
154
  end
144
155
 
145
156
  #
146
- # If the method_sym or its plural is a field name in the results list, this will tell us
157
+ # If method_sym is a field name in SELECT_FIELDS, we can fetch the list of values.
158
+ #
159
+ def self.respond_to? method_sym, include_private = false
160
+ SELECT_FIELDS.find {|field| field[:name] == method_sym } ? true : super
161
+ end
162
+
163
+ #
164
+ # If method_sym or its plural is a field name in the results list, this will tell us
147
165
  # if we can fetch the list of values. It'll only happen after a successful search.
148
166
  #
149
167
  def respond_to? method_sym, include_private = false
@@ -170,20 +188,58 @@ private
170
188
  @query += @options[:without].map {|s| "-#{s}" } if @options[:without]
171
189
 
172
190
  STRING_FIELDS.each {|f| @query << "#{f}:#{@options[f]}" if @options[f] }
173
- SELECT_FIELDS.each {|f| @query << "#{f[:id]}:#{@options[f[:name]]}" if @options[f[:name]].to_i > 0 }
174
191
  SWITCH_FIELDS.each {|f| @query << "#{f}:1" if @options[f] }
192
+ SELECT_FIELDS.each do |f|
193
+ if (@options[f[:label]].to_s.to_i > 0 and f[:id].to_s['_id']) or
194
+ (@options[f[:label]] and not f[:id].to_s['_id'])
195
+ @query << "#{f[:id]}:#{@options[f[:label]]}"
196
+ end
197
+ end
198
+ end
199
+
200
+ #
201
+ # Get a list of options for a particular selection field from the advanced search form
202
+ #
203
+ # Raises an error unless the label is in SELECT_FIELDS
204
+ #
205
+ def self.field_options label
206
+ begin
207
+ raise 'Unknown search field' unless SELECT_FIELDS.find {|f| f[:label] == label.to_sym }
208
+
209
+ opts = (@@doc ||= Nokogiri::HTML(open(ADVANCED_URL))).css('table.formtable td').find do |e|
210
+ e.text[/#{label.to_s}/i]
211
+ end.next_element.first_element_child.children
212
+
213
+ unless (group = opts.css('optgroup')).empty?
214
+ # Categories
215
+ group.inject({}) {|c, og| c[og.attributes['label'].value] = og.children.map {|o| o.attributes['value'].value }; c }
216
+ else
217
+ # Times, languages, platforms
218
+ opts.reject {|o| o.attributes.empty? }.inject({}) {|p, o| p[o.text] = o.attributes['value'].value; p }
219
+ end
220
+ rescue => e
221
+ { :error => e }
222
+ end
223
+ end
224
+
225
+ #
226
+ # If method_sym is a field name in SELECT_FIELDS, fetch the list of values.
227
+ #
228
+ def self.method_missing method_sym, *args, &block
229
+ if respond_to? method_sym
230
+ return self.field_options SELECT_FIELDS.find {|field| field[:name] == method_sym }[:label]
231
+ end
232
+ super
175
233
  end
176
234
 
177
235
  #
178
236
  # If method_sym or its plural form is a field name in the results list, fetch the list of values.
179
237
  # Can only happen after a successful search.
180
238
  #
181
- def method_missing method_sym, *arguments, &block
182
- # Don't need no fancy schmancy pluralizing method. Just try chopping off the 's'.
183
- m = method_sym.to_s.chop.to_sym
184
- if not (@results.empty? or @results.last.empty?) and
185
- (@results.last.first[method_sym] or @results.last.first[m])
186
- return @results.compact.map {|rs| rs.map {|r| r[method_sym] || r[m] } }.flatten
239
+ def method_missing method_sym, *args, &block
240
+ if respond_to? method_sym
241
+ # Don't need no fancy schmancy singularizing method. Just try chopping off the 's'.
242
+ return @results.compact.map {|rs| rs.map {|r| r[method_sym] || r[method_sym.to_s.chop.to_sym] } }.flatten
187
243
  end
188
244
  super
189
245
  end
@@ -1,3 +1,5 @@
1
1
  class Kat
2
- VERSION = '0.3.0'
2
+ NAME = 'Kickass Torrents Search'
3
+ VERSION = '1.0.0'
4
+ AUTHOR = 'Fission Xuiptz'
3
5
  end
@@ -1,256 +1,122 @@
1
1
  require 'minitest/autorun'
2
-
3
- begin
4
- require 'minitest/pride'
5
- rescue LoadError
6
- end
7
-
8
2
  require 'kat'
9
3
 
4
+ blue_peter = Kat.new
5
+ blue_peter.do_search.do_search 1
6
+
10
7
  describe Kat do
11
- before do
12
- @kat = { :vanilla => Kat.new,
13
- :basic => Kat.new('test'),
14
- :advanced => Kat.new('test', { :category => 'books' }) }
15
- end
16
8
 
17
- # Quick search tests
9
+ let(:kat) { Kat.new 'test' }
10
+ let(:kat_opts) { Kat.new 'test', { :category => 'books' } }
18
11
 
19
- describe 'when quick searching' do
20
- it 'returns a result set' do
21
- Kat.search('test').must_be_instance_of Array
12
+ describe 'basic search' do
13
+ it 'returns a full result set' do
22
14
  Kat.search('test').size.must_equal 25
23
15
  end
24
16
  end
25
17
 
26
- # Vanilla query tests
27
-
28
- describe 'when checking if a vanilla query responds to result field before searching' do
29
- it 'returns false' do
30
- [ :titles, :magnets, :downloads, :sizes, :files, :ages, :seeds, :leeches ].each do |s|
31
- @kat[:vanilla].respond_to?(s).must_equal false
32
- end
33
- end
34
- end
35
-
36
- describe 'when checking if a vanilla query responds to result fields after searching' do
37
- it 'returns true' do
38
- @kat[:vanilla].search
39
- [ :titles, :magnets, :downloads, :sizes, :files, :ages, :seeds, :leeches ].each do |s|
40
- @kat[:vanilla].respond_to?(s).must_equal true
41
- end
18
+ describe 'advanced search' do
19
+ it 'returns a valid query string' do
20
+ blue_peter.query_str.must_equal 'new/'
21
+ blue_peter.query_str(1).must_equal 'new/2/'
22
+ kat.query_str.must_equal 'usearch/test/'
23
+ kat_opts.query_str(1).must_equal 'usearch/test category:books/2/'
24
+ kat_opts.query = :foobar
25
+ kat_opts.query_str(1).must_equal 'usearch/foobar category:books/2/'
26
+ kat_opts.query = [ 0, {}, [ :test, 0..1, [ 'user:foo' ] ] ]
27
+ kat_opts.query_str(1).must_equal 'usearch/test user:foo category:books/2/'
42
28
  end
43
- end
44
29
 
45
- describe 'when building a vanilla query' do
46
- it 'returns a query to new torrents' do
47
- @kat[:vanilla].query.must_equal 'new/'
30
+ it 'returns a valid query string based on many options' do
31
+ kat_opts.options = { :files => 2, :safe => true, :language => 2, :sort => :files_count, :asc => true, :seeds => 2 }
32
+ kat_opts.query_str(1).must_equal 'usearch/test seeds:2 files:2 safe:1 category:books lang_id:2/2/?field=files_count&sorder=asc'
48
33
  end
49
- end
50
34
 
51
- describe 'when searching with a vanilla query' do
52
- it 'returns a full result set' do
53
- @kat[:vanilla].search.must_be_instance_of Array
54
- [ :search, :titles, :magnets, :downloads, :sizes, :files, :ages, :seeds, :leeches ].each do |s|
55
- @kat[:vanilla].send(s).size.must_equal 25
35
+ it 'wont respond to result fields before a search' do
36
+ [ :titles, :files ].each do |s|
37
+ kat.respond_to?(s).must_equal false
56
38
  end
57
39
  end
58
- end
59
40
 
60
- describe 'when searching the 2nd page of a vanilla query' do
61
- it 'returns a full result set' do
62
- @kat[:vanilla].search(1).must_be_instance_of Array
63
- @kat[:vanilla].search(1).size.must_equal 25
64
- end
65
- end
66
-
67
- describe 'when searching 2 pages of a vanilla query' do
68
- it 'returns 50 results for each result field' do
69
- @kat[:vanilla].search
70
- @kat[:vanilla].search(1)
71
- if @kat[:vanilla].respond_to? :titles
72
- [ :titles, :magnets, :downloads, :sizes, :files, :ages, :seeds, :leeches ].each do |s|
73
- @kat[:vanilla].send(s).size.must_equal 50
74
- end
75
- else
76
- # Returning a failure, not an error
77
- proc { @kat[:vanilla].titles }.wont_raise NoMethodError
41
+ it 'responds to result fields after a search' do
42
+ [ :titles, :files ].each do |s|
43
+ blue_peter.respond_to?(s).must_equal true
78
44
  end
79
45
  end
80
- end
81
46
 
82
- describe 'when rebuilding a vanilla query' do
83
- it 'returns a query to new torrents' do
84
- @kat[:vanilla].query = nil
85
- @kat[:vanilla].query.must_equal 'new/'
47
+ it 'returns identical result sets' do
48
+ blue_peter.results[0].must_equal blue_peter.search
86
49
  end
87
- end
88
50
 
89
- describe 'when changing the search term on a vanilla query' do
90
- it 'returns a query to usearch' do
91
- @kat[:vanilla].query = 'test'
92
- @kat[:vanilla].query.must_equal 'usearch/test/'
93
- end
94
- end
95
-
96
- describe 'when adding an array of search terms to a vanilla query' do
97
- it 'returns a query to usearch' do
98
- @kat[:vanilla].query = [ 'test', 'category:books' ]
99
- @kat[:vanilla].query.must_equal 'usearch/test category:books/'
100
- end
101
- end
102
-
103
- describe 'when adding an array of crap to a vanilla query' do
104
- it 'returns a valid query' do
105
- @kat[:vanilla].query = [ 0, {}, [ 'test', 0..1 ] ]
106
- @kat[:vanilla].query.must_equal 'usearch/test/'
107
- end
108
- end
109
-
110
- # Basic query tests
111
-
112
- describe 'when checking if a basic query responds to result fields after searching' do
113
- it 'returns true' do
114
- @kat[:basic].search
115
- [ :titles, :magnets, :downloads, :sizes, :files, :ages, :seeds, :leeches ].each do |s|
116
- @kat[:basic].respond_to?(s).must_equal true
117
- end
118
- end
119
- end
120
-
121
- describe 'when building a basic query' do
122
- it 'returns a query to usearch' do
123
- @kat[:basic].query.must_equal 'usearch/test/'
124
- end
125
- end
126
-
127
- describe 'when building a basic query with pages' do
128
- it 'returns a query to usearch with page numbers' do
129
- @kat[:basic].query(1).must_equal 'usearch/test/2/'
130
- end
131
- end
132
-
133
- describe 'when changing the search term of a basic query to nil' do
134
- it 'returns a query to new' do
135
- @kat[:basic].query = nil
136
- @kat[:basic].query.must_equal 'new/'
137
- end
138
- end
139
-
140
- describe 'when adding options to a basic query' do
141
- it 'returns a query to usearch with options' do
142
- @kat[:basic].options = { :category => 'movies' }
143
- @kat[:basic].options.must_equal({ :category => 'movies' })
144
- @kat[:basic].query.must_equal 'usearch/test category:movies/'
145
- @kat[:basic].results.must_be_empty
146
- @kat[:basic].pages.must_be :==, -1
147
- end
148
- end
149
-
150
- describe 'when adding options to a basic query with pages' do
151
- it 'returns a query to usearch with options and page numbers' do
152
- @kat[:basic].options = { :category => 'movies' }
153
- @kat[:basic].options.must_equal({ :category => 'movies' })
154
- @kat[:basic].query(1).must_equal 'usearch/test category:movies/2/'
155
- @kat[:basic].results.must_be_empty
156
- @kat[:basic].pages.must_be :==, -1
157
- end
158
- end
159
-
160
- describe 'when searching with a basic query' do
161
- it 'returns a result set' do
162
- @kat[:basic].search.must_be_instance_of Array
163
- @kat[:basic].search.size.must_equal 25
164
- @kat[:basic].pages.must_be :>, 0
165
- end
166
- end
167
-
168
- describe 'when searching the 2nd page of a basic query' do
169
- it 'returns a result set' do
170
- @kat[:basic].search(1).must_be_instance_of Array
171
- @kat[:basic].search(1).size.must_equal 25
172
- @kat[:basic].pages.must_be :>, 0
51
+ it 'returns a full result set' do
52
+ blue_peter.search(1).size.must_equal 25
53
+ blue_peter.titles.size.must_equal 50
173
54
  end
174
- end
175
55
 
176
- describe 'when searching with the same basic query twice' do
177
- it 'returns the same result set' do
178
- @kat[:basic].search.must_equal @kat[:basic].search
56
+ it 'returns a valid query string with options' do
57
+ bp = blue_peter.dup
58
+ bp.options = { :user => :foobar }
59
+ bp.options.must_equal({ :user => :foobar })
60
+ bp.query_str(1).must_equal 'usearch/user:foobar/2/'
61
+ bp.results.must_be_empty
62
+ bp.pages.must_equal(-1)
179
63
  end
180
- end
181
64
 
182
- describe 'when searching for something that does not exist in a basic query' do
183
- it 'returns an empty set, sets an error and sets pages to 0' do
184
- @kat[:basic].query = 'owijefbvoweivf'
185
- @kat[:basic].search.must_be_nil
186
- @kat[:basic].error.must_be_instance_of Hash
187
- @kat[:basic].error[:error].must_be_instance_of OpenURI::HTTPError
188
- @kat[:basic].error[:error].message.must_equal '404 Not Found'
189
- @kat[:basic].pages.must_equal 0
65
+ it 'can raise an ArgumentError for query=' do
66
+ proc { kat.query = 0 }.must_raise ArgumentError
190
67
  end
191
- end
192
68
 
193
- describe 'when searching for something with 1 page of results in a basic query' do
194
- it 'returns a result set and sets the pages to 1' do
195
- @kat[:basic].options = { :category => 'wallpapers' }
196
- @kat[:basic].options.must_equal({ :category => 'wallpapers' })
197
- @kat[:basic].search.wont_be_nil
198
- @kat[:basic].search.size.wont_equal 0
69
+ it 'can raise an ArgumentError for options=' do
70
+ proc { kat.options = 'foobar' }.must_raise ArgumentError
199
71
  end
200
- end
201
72
 
202
- describe 'when passing query= a Symbol' do
203
- it 'works just like a String' do
204
- @kat[:basic].query = :test
205
- @kat[:basic].query.must_equal 'usearch/test/'
73
+ it 'works when there are fewer than 25 results' do
74
+ kat.options = { :category => :wallpapers }
75
+ kat.search.wont_be_nil
76
+ kat.search.size.wont_equal 0
77
+ kat.pages.must_equal 1
206
78
  end
207
- end
208
79
 
209
- describe 'when passing a non-String-or-Array object to query=' do
210
- it 'raises an ArgumentError' do
211
- proc { @kat[:basic].query = { :foo => 'bar' } }.must_raise ArgumentError
80
+ it 'can return 0 results, set an error and set pages to 0' do
81
+ kat.query = 'owijefbvoweivf'
82
+ kat.search.must_be_nil
83
+ kat.error[:error].must_be_instance_of OpenURI::HTTPError
84
+ kat.error[:error].message.must_equal '404 Not Found'
85
+ kat.pages.must_equal 0
212
86
  end
213
87
  end
214
88
 
215
- describe 'when passing a non-Hash object to options=' do
216
- it 'raises an ArgumentError' do
217
- proc { @kat[:basic].options = 'foobar' }.must_raise ArgumentError
89
+ describe 'field options' do
90
+ it 'returns a list of time added options' do
91
+ times = Kat.times
92
+ times.must_be_instance_of Hash
93
+ times.wont_be_empty
94
+ times[:error].must_be_nil
218
95
  end
219
- end
220
96
 
221
- # Advanced query tests
222
-
223
- describe 'when building an advanced query' do
224
- it 'returns a query with options to usearch' do
225
- @kat[:advanced].query.must_equal 'usearch/test category:books/'
226
- end
227
- end
228
-
229
- describe 'when building an advanced query with pages' do
230
- it 'returns a query with options and page numbers' do
231
- @kat[:advanced].query(1).must_equal 'usearch/test category:books/2/'
97
+ it 'returns a list of categories' do
98
+ categories = Kat.categories
99
+ categories.must_be_instance_of Hash
100
+ categories.wont_be_empty
101
+ categories[:error].must_be_nil
232
102
  end
233
- end
234
103
 
235
- describe 'when building an advanced query with select fields' do
236
- it 'returns a query with options to usearch' do
237
- @kat[:advanced].options = { :language => 2 }
238
- @kat[:advanced].query.must_equal 'usearch/test category:books lang_id:2/'
104
+ it 'returns a list of languages' do
105
+ languages = Kat.languages
106
+ languages.must_be_instance_of Hash
107
+ languages.wont_be_empty
108
+ languages[:error].must_be_nil
239
109
  end
240
- end
241
110
 
242
- describe 'when using symbols instead of strings in an advanced query' do
243
- it 'returns the same query string' do
244
- @kat[:advanced].options = { :category => :books }
245
- @kat[:advanced].query.must_equal 'usearch/test category:books/'
111
+ it 'returns a list of platforms' do
112
+ platforms = Kat.platforms
113
+ platforms.must_be_instance_of Hash
114
+ platforms.wont_be_empty
115
+ platforms[:error].must_be_nil
246
116
  end
247
- end
248
117
 
249
- describe 'when sorting fields' do
250
- it 'adds a sort part to the query string' do
251
- @kat[:advanced].options = { :sort => :size }
252
- @kat[:advanced].query.must_equal 'usearch/test category:books/?field=size&sorder=desc'
118
+ it 'returns an error' do
119
+ Kat.field_options(:foobar)[:error].must_be_instance_of RuntimeError
253
120
  end
254
121
  end
255
-
256
122
  end
metadata CHANGED
@@ -1,32 +1,61 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: kat
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.0
4
+ version: 1.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Fission Xuiptz
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2013-08-09 00:00:00.000000000 Z
11
+ date: 2013-08-14 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: nokogiri
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
- - - '>='
17
+ - - ~>
18
18
  - !ruby/object:Gem::Version
19
- version: '0'
19
+ version: '1.6'
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
- - - '>='
24
+ - - ~>
25
25
  - !ruby/object:Gem::Version
26
- version: '0'
26
+ version: '1.6'
27
+ - !ruby/object:Gem::Dependency
28
+ name: highline
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ~>
32
+ - !ruby/object:Gem::Version
33
+ version: '1.6'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ~>
39
+ - !ruby/object:Gem::Version
40
+ version: '1.6'
41
+ - !ruby/object:Gem::Dependency
42
+ name: trollop
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ~>
46
+ - !ruby/object:Gem::Version
47
+ version: '2.0'
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ~>
53
+ - !ruby/object:Gem::Version
54
+ version: '2.0'
27
55
  description: A Ruby interface to Kickass Torrents
28
56
  email: fissionxuiptz@softwaremojo.com
29
- executables: []
57
+ executables:
58
+ - kat
30
59
  extensions: []
31
60
  extra_rdoc_files: []
32
61
  files:
@@ -36,6 +65,7 @@ files:
36
65
  - LICENSE
37
66
  - README.md
38
67
  - Rakefile
68
+ - bin/kat
39
69
  - kat.gemspec
40
70
  - lib/kat.rb
41
71
  - lib/kat/version.rb
@@ -59,7 +89,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
59
89
  - !ruby/object:Gem::Version
60
90
  version: '0'
61
91
  requirements: []
62
- rubyforge_project: kat
92
+ rubyforge_project:
63
93
  rubygems_version: 2.0.3
64
94
  signing_key:
65
95
  specification_version: 4