gem-search 0.0.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.
data/.gitignore ADDED
@@ -0,0 +1,17 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
data/Gemfile ADDED
@@ -0,0 +1,2 @@
1
+ source 'https://rubygems.org'
2
+ gemspec
data/LICENSE ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2012 rochefort
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,84 @@
1
+ # gem-search
2
+
3
+ gem-search is a command line utitlity like rubygems('gem search').
4
+ You can see a download total gem and sort columns.
5
+
6
+
7
+ ## Installation
8
+
9
+ install it yourself as:
10
+
11
+ $ gem install gem-search
12
+
13
+ ## Usage
14
+
15
+ Use the gem-search as follows:
16
+
17
+ ### Sorted by gem name
18
+ gem-search `keyword'
19
+
20
+ e.g.:
21
+
22
+ ```
23
+ $ gem-search webkit
24
+ NAME DL(ver) DL(all)
25
+ -------------------------------------------------- -------- ---------
26
+ capybara-webkit (0.12.1) 24863 185214
27
+ capybara-webkit-remote (0.0.4) 209 838
28
+ gtk-webkit-ruby (0.0.3) 289 289
29
+ guard-jasmine-headless-webkit (0.3.2) 11964 17872
30
+ intentmedia-capybara-webkit (0.7.2.4) 370 1362
31
+ jasmine-headless-webkit (0.8.4) 19444 46147
32
+ otherinbox-capybara-webkit (0.12.0.1) 594 740
33
+ rspec-formatter-webkit (2.2.0) 438 3549
34
+ webkit-rspec-formatter (2.0.2) 613 1573
35
+ ```
36
+
37
+ ### Sorted by DL(ver)
38
+ gem-search `keyword' -s v
39
+
40
+ e.g.:
41
+
42
+ ```
43
+ $ gem-search factory-girl -s v
44
+ NAME DL(ver) DL(all)
45
+ -------------------------------------------------- -------- ---------
46
+ capybara-webkit (0.12.1) 24863 185214
47
+ jasmine-headless-webkit (0.8.4) 19444 46147
48
+ guard-jasmine-headless-webkit (0.3.2) 11964 17872
49
+ webkit-rspec-formatter (2.0.2) 613 1573
50
+ otherinbox-capybara-webkit (0.12.0.1) 594 740
51
+ rspec-formatter-webkit (2.2.0) 438 3549
52
+ intentmedia-capybara-webkit (0.7.2.4) 370 1362
53
+ gtk-webkit-ruby (0.0.3) 289 289
54
+ capybara-webkit-remote (0.0.4) 209 838
55
+ ```
56
+
57
+ ### Sorted by DL(all)
58
+
59
+ gem-search `keyword' -s a
60
+
61
+ e.g.:
62
+
63
+ ```
64
+ $ gem-search webkit -s a
65
+ NAME DL(ver) DL(all)
66
+ -------------------------------------------------- -------- ---------
67
+ capybara-webkit (0.12.1) 24863 185214
68
+ jasmine-headless-webkit (0.8.4) 19444 46147
69
+ guard-jasmine-headless-webkit (0.3.2) 11964 17872
70
+ rspec-formatter-webkit (2.2.0) 438 3549
71
+ webkit-rspec-formatter (2.0.2) 613 1573
72
+ intentmedia-capybara-webkit (0.7.2.4) 370 1362
73
+ capybara-webkit-remote (0.0.4) 209 838
74
+ otherinbox-capybara-webkit (0.12.0.1) 594 740
75
+ gtk-webkit-ruby (0.0.3) 289 289
76
+ ```
77
+
78
+ ## Contributing
79
+
80
+ 1. Fork it
81
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
82
+ 3. Commit your changes (`git commit -am 'Added some feature'`)
83
+ 4. Push to the branch (`git push origin my-new-feature`)
84
+ 5. Create new Pull Request
data/Rakefile ADDED
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env rake
2
+ require "bundler/gem_tasks"
data/bin/gem-search ADDED
@@ -0,0 +1,35 @@
1
+ #!/usr/bin/env ruby
2
+ require 'slop'
3
+
4
+ def opt_description(msgs)
5
+ ind = ' ' * 22
6
+ msgs.inject { |rtn, msg| rtn << "\n#{ind}#{msg}" }
7
+ end
8
+
9
+ opts = Slop.parse(help: true) do
10
+ banner "Usage: gem-search gem_name [options]\n"
11
+ on :s, :sort, opt_description([
12
+ 'Sort by name of item.',
13
+ ' [n]ame (default)',
14
+ ' [v]er (displayed name: DL(ver))',
15
+ ' [a]ll (displayed name: DL(all))'
16
+ ]), :argument => :optional
17
+ on :v, :version, 'Display the version.'
18
+ end
19
+
20
+ OPT_SORT = {
21
+ 'v' => 'version_downloads',
22
+ 'a' => 'downloads',
23
+ }
24
+
25
+ exit if opts['h']
26
+
27
+ $:.unshift File.dirname(__FILE__) + '/../lib'
28
+ require 'gem-search'
29
+ if opts['v']
30
+ puts "gem-search #{Gem::Search::VERSION}"
31
+ exit
32
+ end
33
+
34
+ gs = Gem::Search::CLI.new
35
+ gs.search(ARGV[0], OPT_SORT[opts['sort']])
@@ -0,0 +1,22 @@
1
+ # -*- encoding: utf-8 -*-
2
+ require File.expand_path('../lib/gem-search/version', __FILE__)
3
+
4
+ Gem::Specification.new do |gem|
5
+ gem.authors = ["rochefort"]
6
+ gem.email = ["terasawan@gmail.com"]
7
+ gem.homepage = "https://github.com/rochefort/gem-search"
8
+ gem.summary = "search gems with using rubygems.org API"
9
+ gem.description = gem.summary
10
+
11
+ gem.files = `git ls-files`.split($\)
12
+ gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
13
+ gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
14
+ gem.name = "gem-search"
15
+ gem.require_paths = ["lib"]
16
+ gem.version = Gem::Search::VERSION
17
+
18
+ gem.add_dependency 'slop'
19
+ gem.add_dependency 'json'
20
+
21
+ gem.add_development_dependency 'webmock'
22
+ end
data/lib/gem-search.rb ADDED
@@ -0,0 +1,2 @@
1
+ require 'gem-search/version'
2
+ require 'gem-search/cli'
@@ -0,0 +1,67 @@
1
+ require 'json'
2
+ require 'open-uri'
3
+
4
+ module Gem::Search
5
+ class CLI
6
+ BASE_URL = 'https://rubygems.org'
7
+ SEARCH_URL = "#{BASE_URL}/api/v1/search.json?query="
8
+ DEFAULT_RULED_LINE_SIZE = [50, 8, 9]
9
+
10
+ def search(query, opt_sort='name')
11
+ return unless query
12
+
13
+ opt_sort ||= 'name'
14
+ url = "#{SEARCH_URL}#{query}"
15
+
16
+ begin
17
+ open(url) do |f|
18
+ gems = JSON.parse(f.read)
19
+ if gems.size.zero?
20
+ puts 'We did not find results.'
21
+ return
22
+ end
23
+ fmt_size = ruled_line_size(gems)
24
+ gems_sort!(gems, opt_sort)
25
+ render_header(fmt_size)
26
+ render_body(gems, fmt_size)
27
+ end
28
+ rescue
29
+ puts 'An unexpected Network error has occurred.'
30
+ end
31
+ end
32
+
33
+ private
34
+ def ruled_line_size(gems)
35
+ line_size = DEFAULT_RULED_LINE_SIZE.dup
36
+ max_name_size = gems.map { |gem| "#{gem['name']} (#{gem['version']})".size }.max
37
+ line_size[0] = max_name_size if max_name_size > line_size[0]
38
+ line_size
39
+ end
40
+
41
+ def gems_sort!(gems, opt_sort)
42
+ if opt_sort == 'name'
43
+ gems.sort!{ |x,y| x[opt_sort] <=> y[opt_sort] }
44
+ else
45
+ gems.sort!{ |x,y| y[opt_sort] <=> x[opt_sort] }
46
+ end
47
+ end
48
+
49
+ def render_header(f)
50
+ fmt = "%-#{f[0]}s %#{f[1]}s %#{f[2]}s"
51
+ puts fmt % ['NAME', 'DL(ver)', 'DL(all)']
52
+ puts fmt % ['-'*f[0], '-'*f[1], '-'*f[2]]
53
+ end
54
+
55
+ def render_body(gems, f)
56
+ fmt = "%-#{f[0]}s %#{f[1]}d %#{f[2]}d"
57
+ gems.each do |gem|
58
+ puts fmt % [
59
+ "#{gem['name']} (#{gem['version']})",
60
+ gem['version_downloads'],
61
+ gem['downloads']
62
+ ]
63
+ end
64
+ end
65
+
66
+ end
67
+ end
@@ -0,0 +1,3 @@
1
+ module Gem::Search
2
+ VERSION = "0.0.2"
3
+ end
data/spec/cli_spec.rb ADDED
@@ -0,0 +1,197 @@
1
+ require 'spec_helper'
2
+
3
+ describe Gem::Search::CLI do
4
+ describe '#search' do
5
+ before do
6
+ @cli = Gem::Search::CLI.new
7
+ stub_request(:get, build_search_uri('factory_girl')).
8
+ to_return(:status => 200, :body => dummy_search_result)
9
+ end
10
+
11
+ context 'when a network error occurred' do
12
+ before do
13
+ stub_request(:get, build_search_uri('network_error_orccurred')).
14
+ to_return(:status => 500, :body => '[]')
15
+ end
16
+ it 'should display a network error message' do
17
+ capture(:stdout) { @cli.search('network_error_orccurred') }.should == "An unexpected Network error has occurred.\n"
18
+ end
19
+ end
20
+
21
+ context 'with nonexistence gem' do
22
+ before do
23
+ stub_request(:get, build_search_uri('no_match_gem_name')).
24
+ to_return(:status => 200, :body => '[]')
25
+ end
26
+ it 'should display a nonexistence message' do
27
+ capture(:stdout) { @cli.search('no_match_gem_name') }.should == "We did not find results.\n"
28
+ end
29
+ end
30
+
31
+ context 'with existing gem' do
32
+ context 'with no sort option' do
33
+ it 'should display rubygems ordering by name' do
34
+ capture(:stdout) { @cli.search('factory_girl') }.should == <<-'EOS'
35
+ NAME DL(ver) DL(all)
36
+ -------------------------------------------------- -------- ---------
37
+ factory_girl (3.6.0) 541 2042859
38
+ factory_girl_generator (0.0.3) 8015 15547
39
+ factory_girl_rails (3.5.0) 39724 1238780
40
+ EOS
41
+ end
42
+ end
43
+
44
+ context 'with sort option: [vd]version_downloads' do
45
+ it "should display rubygems ordering by name" do
46
+ capture(:stdout) { @cli.search('factory_girl', 'version_downloads') }.should == <<'EOS'
47
+ NAME DL(ver) DL(all)
48
+ -------------------------------------------------- -------- ---------
49
+ factory_girl_rails (3.5.0) 39724 1238780
50
+ factory_girl_generator (0.0.3) 8015 15547
51
+ factory_girl (3.6.0) 541 2042859
52
+ EOS
53
+ end
54
+ end
55
+
56
+ context 'with sort option: [d]download' do
57
+ it "should display rubygems ordering by name" do
58
+ capture(:stdout) { @cli.search('factory_girl', 'download') }.should == <<'EOS'
59
+ NAME DL(ver) DL(all)
60
+ -------------------------------------------------- -------- ---------
61
+ factory_girl (3.6.0) 541 2042859
62
+ factory_girl_rails (3.5.0) 39724 1238780
63
+ factory_girl_generator (0.0.3) 8015 15547
64
+ EOS
65
+ end
66
+ end
67
+ end
68
+
69
+ describe 'ruled NAME line' do
70
+ context 'NAME size is 42' do
71
+ before do
72
+ stub_request(:get, build_search_uri('size_is_42_2345678901234567890123456789012')).
73
+ to_return(:status => 200, :body => dummy_search_result_name_size_is_42)
74
+ end
75
+ it "should be 50 characters" do
76
+ capture(:stdout) { @cli.search('size_is_42_2345678901234567890123456789012') }.should == <<'EOS'
77
+ NAME DL(ver) DL(all)
78
+ -------------------------------------------------- -------- ---------
79
+ size_is_42_2345678901234567890123456789012 (0.0.1) 100 1000
80
+ EOS
81
+ end
82
+ end
83
+
84
+ context 'NAME size is 43' do
85
+ before do
86
+ stub_request(:get, build_search_uri('size_is_42_2345678901234567890123456789012')).
87
+ to_return(:status => 200, :body => dummy_search_result_name_size_is_43)
88
+ end
89
+ it "should be 51 characters" do
90
+ capture(:stdout) { @cli.search('size_is_42_2345678901234567890123456789012') }.should == <<'EOS'
91
+ NAME DL(ver) DL(all)
92
+ --------------------------------------------------- -------- ---------
93
+ size_is_43_23456789012345678901234567890123 (0.0.2) 200 2000
94
+ EOS
95
+ end
96
+ end
97
+ end
98
+ end
99
+
100
+ private
101
+ def build_search_uri(query)
102
+ "#{Gem::Search::CLI::SEARCH_URL}#{query}"
103
+ end
104
+
105
+ def dummy_search_result
106
+ # top 3 gems searching with 'factory_girl'
107
+ # https://rubygems.org/api/v1/search.json?query=factory_girl
108
+ [{"name"=>"factory_girl",
109
+ "downloads"=>2042859,
110
+ "version"=>"3.6.0",
111
+ "version_downloads"=>541,
112
+ "platform"=>"ruby",
113
+ "authors"=>"Josh Clayton, Joe Ferris",
114
+ "info"=>
115
+ "factory_girl provides a framework and DSL for defining and\n using factories - less error-prone, more explicit, and\n all-around easier to work with than fixtures.",
116
+ "project_uri"=>"http://rubygems.org/gems/factory_girl",
117
+ "gem_uri"=>"http://rubygems.org/gems/factory_girl-3.6.0.gem",
118
+ "homepage_uri"=>"https://github.com/thoughtbot/factory_girl",
119
+ "wiki_uri"=>"",
120
+ "documentation_uri"=>"",
121
+ "mailing_list_uri"=>"",
122
+ "source_code_uri"=>"https://github.com/thoughtbot/factory_girl",
123
+ "bug_tracker_uri"=>"",
124
+ "dependencies"=>
125
+ {"development"=>
126
+ [{"name"=>"appraisal", "requirements"=>"~> 0.4"},
127
+ {"name"=>"aruba", "requirements"=>">= 0"},
128
+ {"name"=>"bourne", "requirements"=>">= 0"},
129
+ {"name"=>"cucumber", "requirements"=>"~> 1.1"},
130
+ {"name"=>"mocha", "requirements"=>">= 0"},
131
+ {"name"=>"rspec", "requirements"=>"~> 2.0"},
132
+ {"name"=>"simplecov", "requirements"=>">= 0"},
133
+ {"name"=>"sqlite3-ruby", "requirements"=>">= 0"},
134
+ {"name"=>"timecop", "requirements"=>">= 0"},
135
+ {"name"=>"yard", "requirements"=>">= 0"}],
136
+ "runtime"=>[{"name"=>"activesupport", "requirements"=>">= 3.0.0"}]}},
137
+ {"name"=>"factory_girl_rails",
138
+ "downloads"=>1238780,
139
+ "version"=>"3.5.0",
140
+ "version_downloads"=>39724,
141
+ "platform"=>"ruby",
142
+ "authors"=>"Joe Ferris",
143
+ "info"=>
144
+ "factory_girl_rails provides integration between\n factory_girl and rails 3 (currently just automatic factory definition\n loading)",
145
+ "project_uri"=>"http://rubygems.org/gems/factory_girl_rails",
146
+ "gem_uri"=>"http://rubygems.org/gems/factory_girl_rails-3.5.0.gem",
147
+ "homepage_uri"=>"http://github.com/thoughtbot/factory_girl_rails",
148
+ "wiki_uri"=>nil,
149
+ "documentation_uri"=>nil,
150
+ "mailing_list_uri"=>nil,
151
+ "source_code_uri"=>nil,
152
+ "bug_tracker_uri"=>nil,
153
+ "dependencies"=>
154
+ {"development"=>
155
+ [{"name"=>"aruba", "requirements"=>">= 0"},
156
+ {"name"=>"cucumber", "requirements"=>"~> 1.0.0"},
157
+ {"name"=>"rails", "requirements"=>"= 3.0.7"},
158
+ {"name"=>"rake", "requirements"=>">= 0"},
159
+ {"name"=>"rspec", "requirements"=>"~> 2.6.0"}],
160
+ "runtime"=>
161
+ [{"name"=>"factory_girl", "requirements"=>"~> 3.5.0"},
162
+ {"name"=>"railties", "requirements"=>">= 3.0.0"}]}},
163
+ {"name"=>"factory_girl_generator",
164
+ "downloads"=>15547,
165
+ "version"=>"0.0.3",
166
+ "version_downloads"=>8015,
167
+ "platform"=>"ruby",
168
+ "authors"=>"Les Hill",
169
+ "info"=>"Rails 3 generator for factory_girl",
170
+ "project_uri"=>"http://rubygems.org/gems/factory_girl_generator",
171
+ "gem_uri"=>"http://rubygems.org/gems/factory_girl_generator-0.0.3.gem",
172
+ "homepage_uri"=>"http://github.com/leshill/factory_girl_generator",
173
+ "wiki_uri"=>nil,
174
+ "documentation_uri"=>nil,
175
+ "mailing_list_uri"=>nil,
176
+ "source_code_uri"=>nil,
177
+ "bug_tracker_uri"=>nil,
178
+ "dependencies"=>{"development"=>[], "runtime"=>[]}}
179
+ ].to_json
180
+ end
181
+
182
+ def dummy_search_result_name_size_is_42
183
+ [{"name"=>"size_is_42_2345678901234567890123456789012",
184
+ "downloads"=>1000,
185
+ "version"=>"0.0.1",
186
+ "version_downloads"=>100}
187
+ ].to_json
188
+ end
189
+
190
+ def dummy_search_result_name_size_is_43
191
+ [{"name"=>"size_is_43_23456789012345678901234567890123",
192
+ "downloads"=>2000,
193
+ "version"=>"0.0.2",
194
+ "version_downloads"=>200}
195
+ ].to_json
196
+ end
197
+ end
@@ -0,0 +1,19 @@
1
+ # -*- encoding: utf-8 -*-
2
+ require 'rubygems'
3
+ require 'webmock/rspec'
4
+ require 'gem-search'
5
+
6
+ # http://d.hatena.ne.jp/POCHI_BLACK/20100324
7
+ # this method is written by wycats
8
+ def capture(stream)
9
+ begin
10
+ stream = stream.to_s
11
+ eval "$#{stream} = StringIO.new"
12
+ yield
13
+ result = eval("$#{stream}").string
14
+ ensure
15
+ eval("$#{stream} = #{stream.upcase}")
16
+ end
17
+
18
+ result
19
+ end
metadata ADDED
@@ -0,0 +1,108 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: gem-search
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.2
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - rochefort
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2012-08-05 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: slop
16
+ requirement: !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ! '>='
20
+ - !ruby/object:Gem::Version
21
+ version: '0'
22
+ type: :runtime
23
+ prerelease: false
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ! '>='
28
+ - !ruby/object:Gem::Version
29
+ version: '0'
30
+ - !ruby/object:Gem::Dependency
31
+ name: json
32
+ requirement: !ruby/object:Gem::Requirement
33
+ none: false
34
+ requirements:
35
+ - - ! '>='
36
+ - !ruby/object:Gem::Version
37
+ version: '0'
38
+ type: :runtime
39
+ prerelease: false
40
+ version_requirements: !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ! '>='
44
+ - !ruby/object:Gem::Version
45
+ version: '0'
46
+ - !ruby/object:Gem::Dependency
47
+ name: webmock
48
+ requirement: !ruby/object:Gem::Requirement
49
+ none: false
50
+ requirements:
51
+ - - ! '>='
52
+ - !ruby/object:Gem::Version
53
+ version: '0'
54
+ type: :development
55
+ prerelease: false
56
+ version_requirements: !ruby/object:Gem::Requirement
57
+ none: false
58
+ requirements:
59
+ - - ! '>='
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ description: search gems with using rubygems.org API
63
+ email:
64
+ - terasawan@gmail.com
65
+ executables:
66
+ - gem-search
67
+ extensions: []
68
+ extra_rdoc_files: []
69
+ files:
70
+ - .gitignore
71
+ - Gemfile
72
+ - LICENSE
73
+ - README.md
74
+ - Rakefile
75
+ - bin/gem-search
76
+ - gem-search.gemspec
77
+ - lib/gem-search.rb
78
+ - lib/gem-search/cli.rb
79
+ - lib/gem-search/version.rb
80
+ - spec/cli_spec.rb
81
+ - spec/spec_helper.rb
82
+ homepage: https://github.com/rochefort/gem-search
83
+ licenses: []
84
+ post_install_message:
85
+ rdoc_options: []
86
+ require_paths:
87
+ - lib
88
+ required_ruby_version: !ruby/object:Gem::Requirement
89
+ none: false
90
+ requirements:
91
+ - - ! '>='
92
+ - !ruby/object:Gem::Version
93
+ version: '0'
94
+ required_rubygems_version: !ruby/object:Gem::Requirement
95
+ none: false
96
+ requirements:
97
+ - - ! '>='
98
+ - !ruby/object:Gem::Version
99
+ version: '0'
100
+ requirements: []
101
+ rubyforge_project:
102
+ rubygems_version: 1.8.23
103
+ signing_key:
104
+ specification_version: 3
105
+ summary: search gems with using rubygems.org API
106
+ test_files:
107
+ - spec/cli_spec.rb
108
+ - spec/spec_helper.rb