gem-search 0.1.1 → 0.1.2

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: d6ff3a0f935a8163dae5b0184b2244d681de1b1b
4
- data.tar.gz: e3ae44d76970cfabf800fbc3fe3db8d0fb69764c
3
+ metadata.gz: 4a1e1368ab020ee422a5df16ebed3581a5d1d295
4
+ data.tar.gz: bf0313e4e6bbc42fdbff3b5f51f781048531ceb2
5
5
  SHA512:
6
- metadata.gz: 01886f5d4122f7e45c08ad2042a0540079f821ef86c7363af4440b8fcf39d6c3e9e2f4e00ddbb980aa3d1b60948c268cf33e7ffa2d0f6ee7266f30d4c5f20a56
7
- data.tar.gz: 40d0eb2af445c882777d04aefe62aa03b65fd42718594a4acd3f1a1fc570510c75bd25ded9ea399ff5447dbf29aab3558498ccb302b1be50338aba014bb7cf2b
6
+ metadata.gz: d95848032e753ecb45d4757ccb2a951e4da0a3dc2983822b533a8bc6a824a8d847dfa1f30e9221190c8a799e4c415a08775614b9733df301ce3e994d6f4cd421
7
+ data.tar.gz: 0e6b871fcc56fb661ae43db82a2812c01f506cc59b480d124778743ca8e48025008c0098e0406e3450ab6f915ff9dc04472285dbc64088f687e42080331d692a
data/.gitignore CHANGED
@@ -16,3 +16,4 @@ spec/reports
16
16
  test/tmp
17
17
  test/version_tmp
18
18
  tmp
19
+ TODO.txt
@@ -1,3 +1,8 @@
1
+ ## v0.1.2
2
+
3
+ * Correspond to linux with browse option [80bb881]
4
+ * Implement a feature that is to open homepage url by a default browser. [49d2924]
5
+
1
6
  ## v0.1.1
2
7
 
3
8
  * Change default sort option from n[ame] to do a[ll] (download) [7041464]
data/README.md CHANGED
@@ -19,8 +19,32 @@ install it yourself as:
19
19
 
20
20
  Use the gem-search as follows:
21
21
 
22
- ### Sorted by gem name
22
+
23
+ ### Sorted by DL(all)
24
+
23
25
  gem-search `keyword'
26
+ or
27
+ gem-search `keyword' -s a
28
+
29
+ e.g.:
30
+
31
+ ```
32
+ $ gem-search webkit
33
+ NAME DL(ver) DL(all)
34
+ -------------------------------------------------- -------- ---------
35
+ capybara-webkit (0.12.1) 24863 185214
36
+ jasmine-headless-webkit (0.8.4) 19444 46147
37
+ guard-jasmine-headless-webkit (0.3.2) 11964 17872
38
+ rspec-formatter-webkit (2.2.0) 438 3549
39
+ webkit-rspec-formatter (2.0.2) 613 1573
40
+ intentmedia-capybara-webkit (0.7.2.4) 370 1362
41
+ capybara-webkit-remote (0.0.4) 209 838
42
+ otherinbox-capybara-webkit (0.12.0.1) 594 740
43
+ gtk-webkit-ruby (0.0.3) 289 289
44
+ ```
45
+
46
+ ### Sorted by gem name
47
+ gem-search `keyword' -s n
24
48
 
25
49
  e.g.:
26
50
 
@@ -59,26 +83,12 @@ gtk-webkit-ruby (0.0.3) 289 289
59
83
  capybara-webkit-remote (0.0.4) 209 838
60
84
  ```
61
85
 
62
- ### Sorted by DL(all)
86
+ ### Browse
87
+ It open rubygem's homepage in the system's default web browser.
63
88
 
64
- gem-search `keyword' -s a
89
+ gem-search browse 'gem_name'
65
90
 
66
- e.g.:
67
91
 
68
- ```
69
- $ gem-search webkit -s a
70
- NAME DL(ver) DL(all)
71
- -------------------------------------------------- -------- ---------
72
- capybara-webkit (0.12.1) 24863 185214
73
- jasmine-headless-webkit (0.8.4) 19444 46147
74
- guard-jasmine-headless-webkit (0.3.2) 11964 17872
75
- rspec-formatter-webkit (2.2.0) 438 3549
76
- webkit-rspec-formatter (2.0.2) 613 1573
77
- intentmedia-capybara-webkit (0.7.2.4) 370 1362
78
- capybara-webkit-remote (0.0.4) 209 838
79
- otherinbox-capybara-webkit (0.12.0.1) 594 740
80
- gtk-webkit-ruby (0.0.3) 289 289
81
- ```
82
92
 
83
93
  ## Contributing
84
94
 
@@ -1,6 +1,4 @@
1
1
  #!/usr/bin/env ruby
2
- $LOAD_PATH.unshift File.expand_path(File.dirname(__FILE__) + '/../lib')
3
- require 'gem-search'
2
+ require 'gem_search'
4
3
 
5
4
  Gem::Search::Command.new.run
6
-
@@ -1,9 +1,9 @@
1
- require File.expand_path('../lib/gem-search/version', __FILE__)
1
+ require File.expand_path('../lib/gem_search/version', __FILE__)
2
2
 
3
3
  def install_message
4
4
  s = ''
5
5
  s << "\xf0\x9f\x8d\xba " if or_over_mac_os_lion?
6
- s << "Thanks for installing!"
6
+ s << 'Thanks for installing!'
7
7
  end
8
8
 
9
9
  def or_over_mac_os_lion?
@@ -11,31 +11,31 @@ def or_over_mac_os_lion?
11
11
 
12
12
  macos_full_version = `/usr/bin/sw_vers -productVersion`.chomp
13
13
  macos_version = macos_full_version[/10\.\d+/]
14
- return macos_version >= '10.7' # 10.7 is lion
14
+ macos_version >= '10.7' # 10.7 is lion
15
15
  end
16
16
 
17
17
  Gem::Specification.new do |gem|
18
- gem.authors = ["rochefort"]
19
- gem.email = ["terasawan@gmail.com"]
20
- gem.homepage = "https://github.com/rochefort/gem-search"
21
- gem.summary = "search gems with using rubygems.org API"
18
+ gem.authors = ['rochefort']
19
+ gem.email = ['terasawan@gmail.com']
20
+ gem.homepage = 'https://github.com/rochefort/gem-search'
21
+ gem.summary = 'search gems with using rubygems.org API'
22
22
  gem.description = gem.summary
23
23
 
24
24
  gem.files = `git ls-files`.split($\)
25
25
  gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
26
26
  gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
27
- gem.name = "gem-search"
28
- gem.require_paths = ["lib"]
27
+ gem.name = 'gem-search'
28
+ gem.require_paths = ['lib']
29
29
  gem.version = Gem::Search::VERSION
30
30
 
31
31
  gem.post_install_message = install_message
32
32
 
33
- gem.add_dependency 'slop', '~>3.5.0'
33
+ gem.add_dependency 'slop', '~>3.6.0'
34
34
  gem.add_dependency 'json', '~>1.8.1'
35
35
 
36
- gem.add_development_dependency 'webmock', '~>1.17.4'
36
+ gem.add_development_dependency 'webmock', '~>1.18.0'
37
37
  gem.add_development_dependency 'rake', '~>10.3.1'
38
38
 
39
- gem.add_development_dependency 'rspec', '~> 2.14.1'
40
- gem.add_development_dependency 'simplecov', '~> 0.8.2'
39
+ gem.add_development_dependency 'rspec', '~> 3.0.0'
40
+ gem.add_development_dependency 'simplecov', '~> 0.9.0'
41
41
  end
@@ -0,0 +1,9 @@
1
+ module Gem
2
+ module Search
3
+ class LibraryNotFound < StandardError; end
4
+ autoload :Command, 'gem_search/command'
5
+ autoload :Executor, 'gem_search/executor'
6
+ autoload :Rendering, 'gem_search/rendering'
7
+ autoload :VERSION, 'gem_search/version'
8
+ end
9
+ end
@@ -18,13 +18,32 @@ module Gem::Search
18
18
  OPTS = Slop.parse(help: true) do
19
19
  banner "Usage: gem-search gem_name [options]\n"
20
20
  on :s, :sort, opt_description([
21
- 'Sort by the item.',
22
- ' default [a]ll',
23
- ' [a]ll :DL(all) eg. gem-search webkit -s a',
24
- ' [v]er :DL(ver) eg. gem-search webkit -s v',
25
- ' [n]ame : eg. gem-search webkit -s n',
26
- ]), :argument => :optional
21
+ 'Sort by the item.',
22
+ ' default [a]ll',
23
+ ' [a]ll :DL(all) eg. gem-search webkit -s a',
24
+ ' [v]er :DL(ver) eg. gem-search webkit -s v',
25
+ ' [n]ame : eg. gem-search webkit -s n',
26
+ ]), argument: :optional
27
27
  on :v, :version, 'Display the version.'
28
+
29
+ command 'browse' do
30
+ description "Open rubygem's homepage in the system's default web browser"
31
+ run do |_opts, args|
32
+ gem = args.first
33
+ executor = Executor.new
34
+ begin
35
+ executor.browse(gem)
36
+ rescue OpenURI::HTTPError
37
+ puts 'No such gem.'
38
+ abort
39
+ rescue => e
40
+ puts e.message
41
+ puts e.stacktrace
42
+ abort
43
+ end
44
+ exit
45
+ end
46
+ end
28
47
  end
29
48
 
30
49
  def run
@@ -47,21 +66,22 @@ module Gem::Search
47
66
  end
48
67
 
49
68
  private
50
- def version
51
- puts "gem-search #{Gem::Search::VERSION}"
52
- exit
53
- end
54
69
 
55
- def validate
56
- if (ARGV.size == 0)
57
- puts OPTS
58
- abort
59
- end
70
+ def version
71
+ puts "gem-search #{Gem::Search::VERSION}"
72
+ exit
73
+ end
60
74
 
61
- if ARGV.any? { |arg| arg.match(/\A-/) }
62
- puts OPTS
63
- exit
64
- end
75
+ def validate
76
+ if (ARGV.size == 0)
77
+ puts OPTS
78
+ abort
65
79
  end
80
+
81
+ if ARGV.any? { |arg| arg.match(/\A-/) }
82
+ puts OPTS
83
+ exit
84
+ end
85
+ end
66
86
  end
67
87
  end
@@ -0,0 +1,79 @@
1
+ require 'json'
2
+ require 'open-uri'
3
+
4
+ module Gem::Search
5
+ class Executor
6
+ include Gem::Search::Rendering
7
+ BASE_URL = 'https://rubygems.org'
8
+ SEARCH_API = "#{BASE_URL}/api/v1/search.json?query=%s&page=%d"
9
+ GEM_API = "#{BASE_URL}/api/v1/gems/%s.json"
10
+ GEM_URL = "#{BASE_URL}/%s"
11
+
12
+ MAX_REQUEST_COUNT = 20
13
+
14
+ def search(query, opt_sort = 'downloads')
15
+ return unless query
16
+ print 'Searching '
17
+ gems = []
18
+ (1..MAX_REQUEST_COUNT).each do |n|
19
+ print '.'
20
+ url = SEARCH_API % [query, n]
21
+ gems_by_page = open_rubygems_api(url)
22
+ break if gems_by_page.size.zero?
23
+ gems += gems_by_page
24
+ end
25
+ puts
26
+
27
+ fail Gem::Search::LibraryNotFound, 'We did not find results.' if gems.size.zero?
28
+ gems_sort!(gems, opt_sort)
29
+ Executor.render(gems)
30
+ end
31
+
32
+ def browse(gem)
33
+ return unless gem
34
+ api_url = GEM_API % gem
35
+ result = open_rubygems_api(api_url)
36
+ url = result['homepage_uri']
37
+ if url.nil? || url.empty?
38
+ url = GEM_URL % gem
39
+ end
40
+ browser_open(url)
41
+ end
42
+
43
+ private
44
+
45
+ # https://github.com/github/hub/blob/9c589396ae38f7b9f98319065ad491149954c152/lib/hub/context.rb#L517
46
+ def browser_open(url)
47
+ cmd = osx? ? 'open' :
48
+ %w[xdg-open cygstart x-www-browser firefox opera mozilla netscape].find { |comm| which comm }
49
+ system(cmd, url)
50
+ end
51
+
52
+ # refer to: https://github.com/github/hub/blob/9c589396ae38f7b9f98319065ad491149954c152/lib/hub/context.rb#L527
53
+ def osx?
54
+ require 'rbconfig'
55
+ RbConfig::CONFIG['host_os'].to_s.include?('darwin')
56
+ end
57
+
58
+ def open_rubygems_api(url)
59
+ option = {}
60
+ proxy = URI.parse(url).find_proxy
61
+ if proxy
62
+ if proxy.user && proxy.password
63
+ option[:proxy_http_basic_authentication] = [proxy, proxy.user, proxy.password]
64
+ else
65
+ option[:proxy] = proxy
66
+ end
67
+ end
68
+ JSON.parse(open(url, option).read)
69
+ end
70
+
71
+ def gems_sort!(gems, opt_sort)
72
+ if opt_sort == 'name'
73
+ gems.sort! { |x, y| x[opt_sort] <=> y[opt_sort] }
74
+ else
75
+ gems.sort! { |x, y| y[opt_sort] <=> x[opt_sort] }
76
+ end
77
+ end
78
+ end
79
+ end
@@ -0,0 +1,41 @@
1
+ module Gem::Search
2
+ module Rendering
3
+ DEFAULT_RULED_LINE_SIZE = [50, 8, 9]
4
+
5
+ def self.included(base)
6
+ base.extend(self)
7
+ end
8
+
9
+ def render(gems)
10
+ ruled_line_size(gems)
11
+ render_to_header
12
+ render_to_body(gems)
13
+ end
14
+
15
+ private
16
+
17
+ def ruled_line_size(gems)
18
+ max_name_size = gems.map { |gem| "#{gem['name'] } (#{gem['version']})".size }.max
19
+ DEFAULT_RULED_LINE_SIZE[0] = max_name_size if max_name_size > DEFAULT_RULED_LINE_SIZE[0]
20
+ end
21
+
22
+ def render_to_header
23
+ f = DEFAULT_RULED_LINE_SIZE
24
+ fmt = "%-#{f[0]}s %#{f[1]}s %#{f[2]}s"
25
+ puts fmt % ['NAME', 'DL(ver)', 'DL(all)']
26
+ puts fmt % ['-'*f[0], '-'*f[1], '-'*f[2]]
27
+ end
28
+
29
+ def render_to_body(gems)
30
+ f = DEFAULT_RULED_LINE_SIZE
31
+ fmt = "%-#{f[0]}s %#{f[1]}d %#{f[2]}d"
32
+ gems.each do |gem|
33
+ puts fmt % [
34
+ "#{gem['name']} (#{gem['version']})",
35
+ gem['version_downloads'],
36
+ gem['downloads']
37
+ ]
38
+ end
39
+ end
40
+ end
41
+ end
@@ -1,3 +1,3 @@
1
1
  module Gem::Search
2
- VERSION = '0.1.1'
2
+ VERSION = '0.1.2'
3
3
  end
@@ -11,16 +11,21 @@ Usage: gem-search gem_name [options]
11
11
  [n]ame : eg. gem-search webkit -s n
12
12
  -v, --version Display the version.
13
13
  -h, --help Display this help message.
14
- EOS
15
14
 
15
+ Available commands:
16
+
17
+ browse Open rubygem's homepage in the system's default web browser
18
+
19
+ See `<command> --help` for more information on a specific command.
20
+ EOS
16
21
 
17
- shared_examples 'display an usage' do
18
- it 'should display an usage' do
22
+ RSpec.shared_examples 'display an usage' do
23
+ it 'display an usage' do
19
24
  should == USAGE
20
25
  end
21
26
  end
22
27
 
23
- describe 'bin/gem-search' do
28
+ RSpec.describe 'bin/gem-search' do
24
29
  context 'with no argument' do
25
30
  subject { `#{BIN}` }
26
31
  it_behaves_like 'display an usage'
@@ -38,7 +43,7 @@ describe 'bin/gem-search' do
38
43
 
39
44
  context 'with -v' do
40
45
  subject { `#{BIN} -v` }
41
- it 'should display an usage' do
46
+ it 'display an usage' do
42
47
  should == "gem-search #{Gem::Search::VERSION}\n"
43
48
  end
44
49
  end
@@ -2,34 +2,34 @@ require 'spec_helper'
2
2
 
3
3
  include Gem::Search
4
4
 
5
- describe Command do
5
+ RSpec.describe Command do
6
6
  describe '#run' do
7
7
  before do
8
8
  @executor = Executor.new
9
- Executor.should_receive(:new).and_return(@executor)
10
- ARGV.stub(:[]).with(0).and_return(query)
11
- stub_request_search(1, dummy_search_result)
12
- stub_request_no_result_with_page(2)
9
+ allow(Executor).to receive(:new).and_return(@executor)
10
+ allow(ARGV).to receive(:[]).with(0).and_return(query)
11
+ stub_request_search(query, 1, dummy_search_result)
12
+ stub_request_search_no_result_with_page(query, 2)
13
13
  end
14
- let(:query) {'factory-girl'}
14
+ let(:query) { 'factory_girl' }
15
15
 
16
16
  context 'with no sort option' do
17
17
  before do
18
- Command::OPTS.stub(:[]).and_return(nil)
18
+ allow(Command::OPTS).to receive(:[]).and_return(nil)
19
19
  end
20
20
  it 'called with no sort option' do
21
- @executor.should_receive(:search).with(query).once
21
+ expect(@executor).to receive(:search).with(query).once
22
22
  Command.new.run
23
23
  end
24
24
  end
25
25
 
26
26
  context 'with sort option' do
27
27
  before do
28
- Command::OPTS.stub(:[]).and_return(nil)
29
- Command::OPTS.stub(:[]).with('sort').and_return('a')
28
+ allow(Command::OPTS).to receive(:[]).and_return(nil)
29
+ allow(Command::OPTS).to receive(:[]).with('sort').and_return('a')
30
30
  end
31
31
  it 'called with sort option' do
32
- @executor.should_receive(:search).with(query, 'downloads').once
32
+ expect(@executor).to receive(:search).with(query, 'downloads').once
33
33
  Command.new.run
34
34
  end
35
35
  end
@@ -2,37 +2,37 @@ require 'spec_helper'
2
2
 
3
3
  include Gem::Search
4
4
 
5
- describe Executor do
6
- describe '#search' do
7
- before do
8
- @executor = Gem::Search::Executor.new
9
- end
5
+ RSpec.describe Executor do
6
+ before do
7
+ @executor = Executor.new
8
+ end
10
9
 
10
+ describe '#search' do
11
11
  context 'when a network error occurred' do
12
12
  before do
13
- stub_request(:get, build_search_uri(query, 1)).
14
- to_return(:status => 500, :body => '[]')
13
+ stub_request(:get, build_search_uri(query, 1))
14
+ .to_return(status: 500, body: '[]')
15
15
  end
16
- let(:query) {'network_error_orccurred'}
17
- it { expect{ @executor.search(query) }.to raise_error(Exception) }
16
+ let(:query) { 'network_error_orccurred' }
17
+ it { expect { @executor.search(query) }.to raise_error(Exception) }
18
18
  end
19
19
 
20
20
  context 'when no matching gem' do
21
- before { stub_request_no_result_with_page(1) }
22
- let(:query) {'no_match_gem_name'}
23
- it { expect{ @executor.search(query) }.to raise_error(LibraryNotFound) }
21
+ before { stub_request_search_no_result_with_page(query, 1) }
22
+ let(:query) { 'no_match_gem_name' }
23
+ it { expect { @executor.search(query) }.to raise_error(LibraryNotFound) }
24
24
  end
25
25
 
26
26
  describe 'sorting' do
27
27
  before do
28
- stub_request_search(1, dummy_search_result)
29
- stub_request_no_result_with_page(2)
28
+ stub_request_search(query, 1, dummy_search_result)
29
+ stub_request_search_no_result_with_page(query, 2)
30
30
  end
31
- let(:query) {'factory_girl'}
31
+ let(:query) { 'factory_girl' }
32
32
 
33
33
  context 'with no sort option' do
34
34
  it 'display rubygems ordering by name' do
35
- capture(:stdout) { @executor.search(query) }.should == <<-'EOS'.unindent
35
+ res = <<-'EOS'.unindent
36
36
  |Searching ..
37
37
  |NAME DL(ver) DL(all)
38
38
  |-------------------------------------------------- -------- ---------
@@ -40,12 +40,13 @@ describe Executor do
40
40
  |factory_girl_rails (3.5.0) 39724 1238780
41
41
  |factory_girl_generator (0.0.3) 8015 15547
42
42
  EOS
43
+ expect { @executor.search(query) }.to output(res).to_stdout
43
44
  end
44
45
  end
45
46
 
46
47
  context 'with sort option: [a]download' do
47
48
  it 'display rubygems ordering by name' do
48
- capture(:stdout) { @executor.search(query, 'download') }.should == <<-'EOS'.unindent
49
+ res = <<-'EOS'.unindent
49
50
  |Searching ..
50
51
  |NAME DL(ver) DL(all)
51
52
  |-------------------------------------------------- -------- ---------
@@ -53,12 +54,13 @@ describe Executor do
53
54
  |factory_girl_rails (3.5.0) 39724 1238780
54
55
  |factory_girl_generator (0.0.3) 8015 15547
55
56
  EOS
57
+ expect { @executor.search(query, 'download') }.to output(res).to_stdout
56
58
  end
57
59
  end
58
60
 
59
61
  context 'with sort option: [v]version_downloads' do
60
62
  it 'display rubygems ordering by name' do
61
- capture(:stdout) { @executor.search(query, 'version_downloads') }.should == <<-'EOS'.unindent
63
+ res = <<-'EOS'.unindent
62
64
  |Searching ..
63
65
  |NAME DL(ver) DL(all)
64
66
  |-------------------------------------------------- -------- ---------
@@ -66,12 +68,13 @@ describe Executor do
66
68
  |factory_girl_generator (0.0.3) 8015 15547
67
69
  |factory_girl (3.6.0) 541 2042859
68
70
  EOS
71
+ expect { @executor.search(query, 'version_downloads') }.to output(res).to_stdout
69
72
  end
70
73
  end
71
74
 
72
75
  context 'with sort option: [n]ame' do
73
76
  it 'display rubygems ordering by name' do
74
- capture(:stdout) { @executor.search(query, 'name') }.should == <<-'EOS'.unindent
77
+ res = <<-'EOS'.unindent
75
78
  |Searching ..
76
79
  |NAME DL(ver) DL(all)
77
80
  |-------------------------------------------------- -------- ---------
@@ -79,20 +82,21 @@ describe Executor do
79
82
  |factory_girl_generator (0.0.3) 8015 15547
80
83
  |factory_girl_rails (3.5.0) 39724 1238780
81
84
  EOS
85
+ expect { @executor.search(query, 'name') }.to output(res).to_stdout
82
86
  end
83
87
  end
84
88
  end
85
89
 
86
90
  describe 'multiple page' do
87
91
  before do
88
- stub_request_search(1, load_http_stubs('cucumber-_1.json'))
89
- stub_request_search(2, load_http_stubs('cucumber-_2.json'))
90
- stub_request_search(3, load_http_stubs('cucumber-_3.json'))
91
- stub_request_no_result_with_page(4)
92
+ stub_request_search(query, 1, load_http_stubs('search/cucumber-_1.json'))
93
+ stub_request_search(query, 2, load_http_stubs('search/cucumber-_2.json'))
94
+ stub_request_search(query, 3, load_http_stubs('search/cucumber-_3.json'))
95
+ stub_request_search_no_result_with_page(query, 4)
92
96
  end
93
97
  let(:query) { 'cucumber-' }
94
98
  it 'display rubygems ordering by name' do
95
- capture(:stdout) { @executor.search(query, 'name') }.should == <<-'EOS'.unindent
99
+ res = <<-'EOS'.unindent
96
100
  |Searching ....
97
101
  |NAME DL(ver) DL(all)
98
102
  |-------------------------------------------------- -------- ---------
@@ -160,58 +164,106 @@ describe Executor do
160
164
  |tasty-cucumber-client (0.1.10) 1504 11518
161
165
  |vagrant-cucumber-host (0.1.14) 163 163
162
166
  EOS
167
+ expect { @executor.search(query, 'name') }.to output(res).to_stdout
163
168
  end
164
169
  end
165
170
 
166
171
  describe 'ruled NAME line' do
167
172
  context 'NAME size is 42' do
168
173
  before do
169
- stub_request_search(1, dummy_search_result_name_size_is_42)
170
- stub_request_no_result_with_page(2)
174
+ stub_request_search(query, 1, dummy_search_result_name_size_is_42)
175
+ stub_request_search_no_result_with_page(query, 2)
171
176
  end
172
- let(:query) {'size_is_42_2345678901234567890123456789012'}
177
+ let(:query) { 'size_is_42_2345678901234567890123456789012' }
173
178
  it 'is 50 characters' do
174
- capture(:stdout) { @executor.search(query) }.should == <<-'EOS'.unindent
179
+ res = <<-'EOS'.unindent
175
180
  |Searching ..
176
181
  |NAME DL(ver) DL(all)
177
182
  |-------------------------------------------------- -------- ---------
178
183
  |size_is_42_2345678901234567890123456789012 (0.0.1) 100 1000
179
184
  EOS
185
+ expect { @executor.search(query) }.to output(res).to_stdout
180
186
  end
181
187
  end
182
188
 
183
189
  context 'NAME size is 43' do
184
190
  before do
185
- stub_request_search(1, dummy_search_result_name_size_is_43)
186
- stub_request_no_result_with_page(2)
191
+ stub_request_search(query, 1, dummy_search_result_name_size_is_43)
192
+ stub_request_search_no_result_with_page(query, 2)
187
193
  end
188
- let(:query) {'size_is_43_23456789012345678901234567890123'}
194
+ let(:query) { 'size_is_43_23456789012345678901234567890123' }
189
195
  it 'is 51 characters' do
190
- capture(:stdout) { @executor.search(query) }.should == <<-'EOS'.unindent
196
+ res = <<-'EOS'.unindent
191
197
  |Searching ..
192
198
  |NAME DL(ver) DL(all)
193
199
  |--------------------------------------------------- -------- ---------
194
200
  |size_is_43_23456789012345678901234567890123 (0.0.2) 200 2000
195
201
  EOS
202
+ expect { @executor.search(query) }.to output(res).to_stdout
196
203
  end
197
204
  end
198
205
  end
199
206
  end
200
207
 
201
- private
202
- def dummy_search_result_name_size_is_42
203
- [{"name"=>"size_is_42_2345678901234567890123456789012",
204
- "downloads"=>1000,
205
- "version"=>"0.0.1",
206
- "version_downloads"=>100}
207
- ].to_json
208
+ describe '#browse' do
209
+ context 'when a network error occurred' do
210
+ before do
211
+ stub_request(:get, build_gems_uri(query))
212
+ .to_return(status: 500, body: '[]')
213
+ end
214
+ let(:query) { 'network_error_orccurred' }
215
+ it { expect { @executor.browse(query) }.to raise_error(Exception) }
216
+ end
217
+
218
+ context 'when no matching gem' do
219
+ before { stub_request_gems_no_result(query) }
220
+ let(:query) { 'no_match_gem_name' }
221
+ it { expect { @executor.browse(query) }.to raise_error(OpenURI::HTTPError) }
222
+ end
223
+
224
+ context 'when no homepage_uri' do
225
+ before do
226
+ url = Executor::GEM_URL % query
227
+ allow(@executor).to receive(:system).with('open', url)
228
+ stub_request_gems(query, load_http_stubs("gems/#{query}.json"))
229
+ end
230
+ let(:query) { 'git-trend_no_homepage' }
231
+
232
+ it 'open a rubygems url' do
233
+ @executor.browse(query)
234
+ end
208
235
  end
209
236
 
210
- def dummy_search_result_name_size_is_43
211
- [{"name"=>"size_is_43_23456789012345678901234567890123",
212
- "downloads"=>2000,
213
- "version"=>"0.0.2",
214
- "version_downloads"=>200}
215
- ].to_json
237
+ context 'when homepage_uri is existed' do
238
+ before do
239
+ http_stub = load_http_stubs("gems/#{query}.json")
240
+ url = JSON.parse(http_stub)['homepage_uri']
241
+ allow(@executor).to receive(:system).with('open', url)
242
+ stub_request_gems(query, http_stub)
243
+ end
244
+ let(:query) { 'git-trend' }
245
+
246
+ it 'open a homepage url' do
247
+ @executor.browse(query)
248
+ end
216
249
  end
250
+ end
251
+
252
+ private
253
+
254
+ def dummy_search_result_name_size_is_42
255
+ [{"name"=>"size_is_42_2345678901234567890123456789012",
256
+ "downloads"=>1000,
257
+ "version"=>"0.0.1",
258
+ "version_downloads"=>100}
259
+ ].to_json
260
+ end
261
+
262
+ def dummy_search_result_name_size_is_43
263
+ [{"name"=>"size_is_43_23456789012345678901234567890123",
264
+ "downloads"=>2000,
265
+ "version"=>"0.0.2",
266
+ "version_downloads"=>200}
267
+ ].to_json
268
+ end
217
269
  end
@@ -0,0 +1,66 @@
1
+ {
2
+ "name": "git-trend",
3
+ "downloads": 1106,
4
+ "version": "0.0.8",
5
+ "version_downloads": 36,
6
+ "platform": "ruby",
7
+ "authors": "rochefort",
8
+ "info": "cli based; show Trending repository on github",
9
+ "licenses": [
10
+ "MIT"
11
+ ],
12
+ "project_uri": "http://rubygems.org/gems/git-trend",
13
+ "gem_uri": "http://rubygems.org/gems/git-trend-0.0.8.gem",
14
+ "homepage_uri": "https://github.com/rochefort/git-trend",
15
+ "wiki_uri": null,
16
+ "documentation_uri": null,
17
+ "mailing_list_uri": null,
18
+ "source_code_uri": null,
19
+ "bug_tracker_uri": null,
20
+ "dependencies": {
21
+ "development": [
22
+ {
23
+ "name": "bundler",
24
+ "requirements": "~> 1.6"
25
+ },
26
+ {
27
+ "name": "coveralls",
28
+ "requirements": ">= 0"
29
+ },
30
+ {
31
+ "name": "rake",
32
+ "requirements": ">= 0"
33
+ },
34
+ {
35
+ "name": "rspec",
36
+ "requirements": "~> 3.0.0"
37
+ },
38
+ {
39
+ "name": "rspec-its",
40
+ "requirements": "~> 1.0.1"
41
+ },
42
+ {
43
+ "name": "simplecov",
44
+ "requirements": "~> 0.9.0"
45
+ },
46
+ {
47
+ "name": "webmock",
48
+ "requirements": "~> 1.18.0"
49
+ }
50
+ ],
51
+ "runtime": [
52
+ {
53
+ "name": "addressable",
54
+ "requirements": "~> 2.3.6"
55
+ },
56
+ {
57
+ "name": "mechanize",
58
+ "requirements": "~> 2.7.3"
59
+ },
60
+ {
61
+ "name": "thor",
62
+ "requirements": "~> 0.19.1"
63
+ }
64
+ ]
65
+ }
66
+ }
@@ -0,0 +1,65 @@
1
+ {
2
+ "name": "git-trend",
3
+ "downloads": 1106,
4
+ "version": "0.0.8",
5
+ "version_downloads": 36,
6
+ "platform": "ruby",
7
+ "authors": "rochefort",
8
+ "info": "cli based; show Trending repository on github",
9
+ "licenses": [
10
+ "MIT"
11
+ ],
12
+ "project_uri": "http://rubygems.org/gems/git-trend",
13
+ "gem_uri": "http://rubygems.org/gems/git-trend-0.0.8.gem",
14
+ "wiki_uri": null,
15
+ "documentation_uri": null,
16
+ "mailing_list_uri": null,
17
+ "source_code_uri": null,
18
+ "bug_tracker_uri": null,
19
+ "dependencies": {
20
+ "development": [
21
+ {
22
+ "name": "bundler",
23
+ "requirements": "~> 1.6"
24
+ },
25
+ {
26
+ "name": "coveralls",
27
+ "requirements": ">= 0"
28
+ },
29
+ {
30
+ "name": "rake",
31
+ "requirements": ">= 0"
32
+ },
33
+ {
34
+ "name": "rspec",
35
+ "requirements": "~> 3.0.0"
36
+ },
37
+ {
38
+ "name": "rspec-its",
39
+ "requirements": "~> 1.0.1"
40
+ },
41
+ {
42
+ "name": "simplecov",
43
+ "requirements": "~> 0.9.0"
44
+ },
45
+ {
46
+ "name": "webmock",
47
+ "requirements": "~> 1.18.0"
48
+ }
49
+ ],
50
+ "runtime": [
51
+ {
52
+ "name": "addressable",
53
+ "requirements": "~> 2.3.6"
54
+ },
55
+ {
56
+ "name": "mechanize",
57
+ "requirements": "~> 2.7.3"
58
+ },
59
+ {
60
+ "name": "thor",
61
+ "requirements": "~> 0.19.1"
62
+ }
63
+ ]
64
+ }
65
+ }
@@ -4,37 +4,40 @@ require 'simplecov'
4
4
  SimpleCov.start
5
5
 
6
6
  require 'webmock/rspec'
7
- require 'gem-search'
7
+ require 'gem_search'
8
8
 
9
- # http://d.hatena.ne.jp/POCHI_BLACK/20100324
10
- # this method is written by wycats
11
- def capture(stream)
12
- begin
13
- stream = stream.to_s
14
- eval "$#{stream} = StringIO.new"
15
- yield
16
- result = eval("$#{stream}").string
17
- ensure
18
- eval("$#{stream} = #{stream.upcase}")
19
- end
20
-
21
- result
9
+ RSpec.configure do |config|
10
+ config.expose_dsl_globally = false
22
11
  end
23
12
 
24
13
  def load_http_stubs(file_name)
25
14
  open(File.join(File.dirname(__FILE__), 'http_stubs', file_name)).read
26
15
  end
27
16
 
28
- def stub_request_search(page, body)
29
- stub_request(:get, build_search_uri(query, page)).to_return(:status => 200, :body => body)
17
+ # stubs for search API
18
+ def stub_request_search(query, page, body)
19
+ stub_request(:get, build_search_uri(query, page)).to_return(status: 200, body: body)
30
20
  end
31
21
 
32
- def stub_request_no_result_with_page(page)
33
- stub_request(:get, build_search_uri(query, page)).to_return(:status => 200, :body => '[]')
22
+ def stub_request_search_no_result_with_page(query, page)
23
+ stub_request(:get, build_search_uri(query, page)).to_return(status: 200, body: '[]')
34
24
  end
35
25
 
36
26
  def build_search_uri(query, page)
37
- Executor::SEARCH_URL % [query, page]
27
+ Executor::SEARCH_API % [query, page]
28
+ end
29
+
30
+ # stubs for gems API
31
+ def stub_request_gems(query, body)
32
+ stub_request(:get, build_gems_uri(query)).to_return(status: 200, body: body)
33
+ end
34
+
35
+ def stub_request_gems_no_result(query)
36
+ stub_request(:get, build_gems_uri(query)).to_return(status: 404, body: '[]')
37
+ end
38
+
39
+ def build_gems_uri(query)
40
+ Executor::GEM_API % query
38
41
  end
39
42
 
40
43
  def dummy_search_result
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: gem-search
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.1
4
+ version: 0.1.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - rochefort
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-06-05 00:00:00.000000000 Z
11
+ date: 2014-08-13 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: slop
@@ -16,14 +16,14 @@ dependencies:
16
16
  requirements:
17
17
  - - "~>"
18
18
  - !ruby/object:Gem::Version
19
- version: 3.5.0
19
+ version: 3.6.0
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: 3.5.0
26
+ version: 3.6.0
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: json
29
29
  requirement: !ruby/object:Gem::Requirement
@@ -44,14 +44,14 @@ dependencies:
44
44
  requirements:
45
45
  - - "~>"
46
46
  - !ruby/object:Gem::Version
47
- version: 1.17.4
47
+ version: 1.18.0
48
48
  type: :development
49
49
  prerelease: false
50
50
  version_requirements: !ruby/object:Gem::Requirement
51
51
  requirements:
52
52
  - - "~>"
53
53
  - !ruby/object:Gem::Version
54
- version: 1.17.4
54
+ version: 1.18.0
55
55
  - !ruby/object:Gem::Dependency
56
56
  name: rake
57
57
  requirement: !ruby/object:Gem::Requirement
@@ -72,28 +72,28 @@ dependencies:
72
72
  requirements:
73
73
  - - "~>"
74
74
  - !ruby/object:Gem::Version
75
- version: 2.14.1
75
+ version: 3.0.0
76
76
  type: :development
77
77
  prerelease: false
78
78
  version_requirements: !ruby/object:Gem::Requirement
79
79
  requirements:
80
80
  - - "~>"
81
81
  - !ruby/object:Gem::Version
82
- version: 2.14.1
82
+ version: 3.0.0
83
83
  - !ruby/object:Gem::Dependency
84
84
  name: simplecov
85
85
  requirement: !ruby/object:Gem::Requirement
86
86
  requirements:
87
87
  - - "~>"
88
88
  - !ruby/object:Gem::Version
89
- version: 0.8.2
89
+ version: 0.9.0
90
90
  type: :development
91
91
  prerelease: false
92
92
  version_requirements: !ruby/object:Gem::Requirement
93
93
  requirements:
94
94
  - - "~>"
95
95
  - !ruby/object:Gem::Version
96
- version: 0.8.2
96
+ version: 0.9.0
97
97
  description: search gems with using rubygems.org API
98
98
  email:
99
99
  - terasawan@gmail.com
@@ -111,17 +111,19 @@ files:
111
111
  - Rakefile
112
112
  - bin/gem-search
113
113
  - gem-search.gemspec
114
- - lib/gem-search.rb
115
- - lib/gem-search/command.rb
116
- - lib/gem-search/executor.rb
117
- - lib/gem-search/rendering.rb
118
- - lib/gem-search/version.rb
119
- - spec/bin/gem-search_spec.rb
114
+ - lib/gem_search.rb
115
+ - lib/gem_search/command.rb
116
+ - lib/gem_search/executor.rb
117
+ - lib/gem_search/rendering.rb
118
+ - lib/gem_search/version.rb
119
+ - spec/bin/gem_search_spec.rb
120
120
  - spec/command_spec.rb
121
121
  - spec/executor_spec.rb
122
- - spec/http_stubs/cucumber-_1.json
123
- - spec/http_stubs/cucumber-_2.json
124
- - spec/http_stubs/cucumber-_3.json
122
+ - spec/http_stubs/gems/git-trend.json
123
+ - spec/http_stubs/gems/git-trend_no_homepage.json
124
+ - spec/http_stubs/search/cucumber-_1.json
125
+ - spec/http_stubs/search/cucumber-_2.json
126
+ - spec/http_stubs/search/cucumber-_3.json
125
127
  - spec/spec_helper.rb
126
128
  homepage: https://github.com/rochefort/gem-search
127
129
  licenses: []
@@ -147,10 +149,12 @@ signing_key:
147
149
  specification_version: 4
148
150
  summary: search gems with using rubygems.org API
149
151
  test_files:
150
- - spec/bin/gem-search_spec.rb
152
+ - spec/bin/gem_search_spec.rb
151
153
  - spec/command_spec.rb
152
154
  - spec/executor_spec.rb
153
- - spec/http_stubs/cucumber-_1.json
154
- - spec/http_stubs/cucumber-_2.json
155
- - spec/http_stubs/cucumber-_3.json
155
+ - spec/http_stubs/gems/git-trend.json
156
+ - spec/http_stubs/gems/git-trend_no_homepage.json
157
+ - spec/http_stubs/search/cucumber-_1.json
158
+ - spec/http_stubs/search/cucumber-_2.json
159
+ - spec/http_stubs/search/cucumber-_3.json
156
160
  - spec/spec_helper.rb
@@ -1,9 +0,0 @@
1
- module Gem
2
- module Search
3
- class LibraryNotFound < StandardError; end
4
- autoload :Command , 'gem-search/command'
5
- autoload :Executor , 'gem-search/executor'
6
- autoload :Rendering, 'gem-search/rendering'
7
- autoload :VERSION , 'gem-search/version'
8
- end
9
- end
@@ -1,52 +0,0 @@
1
- require 'json'
2
- require 'open-uri'
3
-
4
- module Gem::Search
5
- class Executor
6
- include Gem::Search::Rendering
7
- BASE_URL = 'https://rubygems.org'
8
- SEARCH_URL = "#{BASE_URL}/api/v1/search.json?query=%s&page=%d"
9
- MAX_REQUEST_COUNT = 20
10
-
11
- def search(query, opt_sort='downloads')
12
- return unless query
13
- print 'Searching '
14
- gems = []
15
- (1..MAX_REQUEST_COUNT).each do |n|
16
- print '.'
17
- url = SEARCH_URL % [query, n]
18
- gems_by_page = search_rubygems(url)
19
- break if gems_by_page.size.zero?
20
- gems += gems_by_page
21
- end
22
- puts
23
-
24
- raise Gem::Search::LibraryNotFound, 'We did not find results.' if gems.size.zero?
25
- gems_sort!(gems, opt_sort)
26
- Executor.render(gems)
27
- end
28
-
29
- private
30
- def search_rubygems(url)
31
- option = {}
32
- proxy = URI.parse(url).find_proxy
33
- if proxy
34
- if proxy.user && proxy.password
35
- option[:proxy_http_basic_authentication] = [proxy, proxy.user, proxy.password]
36
- else
37
- option[:proxy] = proxy
38
- end
39
- end
40
- JSON.parse(open(url, option).read)
41
- end
42
-
43
- def gems_sort!(gems, opt_sort)
44
- if opt_sort == 'name'
45
- gems.sort!{ |x,y| x[opt_sort] <=> y[opt_sort] }
46
- else
47
- gems.sort!{ |x,y| y[opt_sort] <=> x[opt_sort] }
48
- end
49
- end
50
-
51
- end
52
- end
@@ -1,42 +0,0 @@
1
- module Gem::Search
2
- module Rendering
3
- DEFAULT_RULED_LINE_SIZE = [50, 8, 9]
4
-
5
- def self.included(base)
6
- base.extend(self)
7
- end
8
-
9
- def render(gems)
10
- set_ruled_line_size(gems)
11
- render_to_header
12
- render_to_body(gems)
13
- end
14
-
15
- private
16
- def set_ruled_line_size(gems)
17
- max_name_size = gems.map { |gem| "#{gem['name'] } (#{gem['version']})".size }.max
18
- if max_name_size > DEFAULT_RULED_LINE_SIZE[0]
19
- DEFAULT_RULED_LINE_SIZE[0] = max_name_size
20
- end
21
- end
22
-
23
- def render_to_header
24
- f=DEFAULT_RULED_LINE_SIZE
25
- fmt = "%-#{f[0]}s %#{f[1]}s %#{f[2]}s"
26
- puts fmt % ['NAME', 'DL(ver)', 'DL(all)']
27
- puts fmt % ['-'*f[0], '-'*f[1], '-'*f[2]]
28
- end
29
-
30
- def render_to_body(gems)
31
- f=DEFAULT_RULED_LINE_SIZE
32
- fmt = "%-#{f[0]}s %#{f[1]}d %#{f[2]}d"
33
- gems.each do |gem|
34
- puts fmt % [
35
- "#{gem['name']} (#{gem['version']})",
36
- gem['version_downloads'],
37
- gem['downloads']
38
- ]
39
- end
40
- end
41
- end
42
- end