gem-search 0.1.1 → 0.1.2

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.
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