annotate_gem 0.0.8

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 7e0ee9922534ca6c7e763fd617f8e81a461ff4e1
4
+ data.tar.gz: d60f74fff3ca5131bd5beacbc7729435a973ab01
5
+ SHA512:
6
+ metadata.gz: 3323eb1ba24e40ca46fb3f75c4ccb72ead72c4c9279fcebe841ee24b7de4eb51af7aa0fd3dd162d2367da6f6e3ea74aabb5c2748bf41cecff5e8d3a92b2c166c
7
+ data.tar.gz: cbb7b96c3789ff8123299bc315742c727521b1f9eee40abf53c9f3078a4b1033b3ca19e9ae16e9820093cb8fc901c3694448bea26207293df302dc830c9a40ad
data/.gitignore ADDED
@@ -0,0 +1,15 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /Gemfile.lock
4
+ /_yardoc/
5
+ /coverage/
6
+ /doc/
7
+ /pkg/
8
+ /spec/reports/
9
+ /tmp/
10
+ *.bundle
11
+ *.so
12
+ *.o
13
+ *.a
14
+ mkmf.log
15
+ vendor
data/Gemfile ADDED
@@ -0,0 +1,7 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in grub.gemspec
4
+ gemspec
5
+
6
+ # An IRB alternative and runtime developer console (http://pryrepl.org)
7
+ gem "pry"
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2016 Ivan Tse
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,60 @@
1
+ # AnnotateGem
2
+
3
+ `annotate_gem` is command line tool that will add useful comments to your Gemfile. For each gem, `annotate_gem` will create a comment with the gem's description and the gem's website. For example, a Gemfile containing the following
4
+
5
+ ```ruby
6
+ gem "rails"
7
+ gem "nokogiri"
8
+ gem "brakeman"
9
+ ```
10
+
11
+ will be converted into something that is more descriptive and is self-documenting:
12
+
13
+ ```ruby
14
+ # Full-stack web application framework. (http://www.rubyonrails.org)
15
+ gem "rails"
16
+ # Nokogiri (鋸) is an HTML, XML, SAX, and Reader parser (http://nokogiri.org)
17
+ gem "nokogiri"
18
+ # Security vulnerability scanner for Ruby on Rails. (http://brakemanscanner.org)
19
+ gem "brakeman"
20
+ ```
21
+
22
+ The motivation for `annotate_gem` is that developers often open a Gemfile and not know what many of the listed gems are actually for. It's hard to track down which gem is providing which functionality. This is a common problem since many gem names do not reflect the actual feature.
23
+
24
+ If you do _not_ want to install the gem, you can also visit <https://annotate_gem.herokuapp.com/> which is a web interface for `annotate_gem`.
25
+
26
+ ## Installation
27
+
28
+ ```
29
+ $ gem install annotate_gem
30
+ ```
31
+
32
+ ## Usage
33
+
34
+ Running `annotate_gem` itself will add comments to the current directory's `Gemfile`.
35
+
36
+ ```
37
+ $ cat Gemfile
38
+ source 'https://rubygems.org'
39
+ gem "pry"
40
+ $ annotate_gem
41
+ $ cat Gemfile
42
+ source 'https://rubygems.org'
43
+ # An IRB alternative and runtime developer console (http://pryrepl.org)
44
+ gem "pry"
45
+ ```
46
+
47
+ `annotate_gem` has several options and you can see them via `annotate_gem -h`. `annotate_gem` also works with specifying a single gem name:
48
+
49
+ ```
50
+ $ annotate_gem aasm
51
+ State machine mixin for Ruby objects (https://github.com/aasm/aasm)
52
+ ```
53
+
54
+ ## Contributing
55
+
56
+ 1. Fork it ( https://github.com/ivantsepp/annotate_gem/fork )
57
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
58
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
59
+ 4. Push to the branch (`git push origin my-new-feature`)
60
+ 5. Create a new Pull Request
data/Rakefile ADDED
@@ -0,0 +1,8 @@
1
+ require "bundler/gem_tasks"
2
+ require "rake/testtask"
3
+
4
+ Rake::TestTask.new do |t|
5
+ t.libs << "test"
6
+ t.test_files = FileList['test/**/*test.rb']
7
+ t.verbose = true
8
+ end
@@ -0,0 +1,28 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'annotate_gem/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "annotate_gem"
8
+ spec.version = AnnotateGem::VERSION
9
+ spec.authors = ["Ivan Tse"]
10
+ spec.email = ["ivan.tse1@gmail.com"]
11
+ spec.summary = AnnotateGem::DESCRIPTION
12
+ spec.description = <<-DESCRIPTION.gsub(/^\s+/, "").gsub(/\n/, " ")
13
+ Clarify your dependencies by adding a detailed comment to each line in Gemfile specifying the
14
+ gem's summary and its website if any.
15
+ DESCRIPTION
16
+ spec.homepage = "https://github.com/ivantsepp/annotate_gem"
17
+ spec.license = "MIT"
18
+
19
+ spec.files = `git ls-files -z`.split("\x0")
20
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
21
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
22
+ spec.require_paths = ["lib"]
23
+
24
+ spec.add_runtime_dependency "bundler", "~> 1.11.2"
25
+ spec.add_development_dependency "rake", "~> 10.0"
26
+ spec.add_development_dependency "minitest", "~> 5.0"
27
+ spec.add_development_dependency "mocha", "~> 1.1"
28
+ end
data/bin/annotate_gem ADDED
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ $:.unshift(File.join(File.dirname(__FILE__), "../lib"))
4
+
5
+ require "annotate_gem/cli"
6
+ require "annotate_gem"
7
+
8
+ AnnotateGem::CLI.new.run(ARGV)
@@ -0,0 +1,8 @@
1
+ require "annotate_gem/version"
2
+ require "bundler"
3
+ require "annotate_gem/gem_line"
4
+ require "annotate_gem/gemfile"
5
+ require "annotate_gem/spec_finder"
6
+
7
+ module AnnotateGem
8
+ end
@@ -0,0 +1,41 @@
1
+ require "annotate_gem/options"
2
+
3
+ module AnnotateGem
4
+ class CLI
5
+ def run(args)
6
+ options = Options.new.parse!(args)
7
+ if args.empty?
8
+ run_for_gemfile(options)
9
+ else
10
+ run_for_gem(args.pop, options)
11
+ end
12
+ end
13
+
14
+ def run_for_gemfile(options = {})
15
+ Bundler.configure
16
+ gemfile = Gemfile.new(Bundler.default_gemfile, options)
17
+ gemfile.parse
18
+ unless gemfile.gem_lines.empty?
19
+ SpecFinder.find_specs_for(gemfile.gem_lines, &self.method(:print_progress))
20
+ gemfile.write_comments
21
+ end
22
+ end
23
+
24
+ def run_for_gem(gem_name, options = {})
25
+ gem_line = GemLine.new(name: gem_name, options: options)
26
+ SpecFinder.find_specs_for(gem_line, &self.method(:print_progress))
27
+
28
+ info = gem_line.info
29
+ info = "No information to show" if info.strip.empty?
30
+ puts info
31
+ end
32
+
33
+ private
34
+
35
+ def print_progress(processing, total)
36
+ print "Fetching gem metadata..." if processing.zero?
37
+ print "."
38
+ print "\n" if processing == total
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,65 @@
1
+ module AnnotateGem
2
+ class GemLine
3
+
4
+ attr_accessor :name, :original_line, :location, :prev_line_comment, :spec, :options
5
+
6
+ def initialize(*args)
7
+ named_params = args.last.respond_to?(:[]) && args.last
8
+ @name = (named_params && named_params[:name]) || args[0]
9
+ @original_line = (named_params && named_params[:original_line]) || args[1]
10
+ @location = (named_params && named_params[:location]) || args[2]
11
+ @prev_line_comment = (named_params && named_params[:prev_line_comment]) || args[3]
12
+ @options = (named_params && named_params[:options]) || named_params
13
+ end
14
+
15
+ def comment
16
+ leading_spaces = original_line[0..leading_spaces_count - 1] if leading_spaces_count > 0
17
+ comment = "#{leading_spaces}# #{info}"
18
+ end
19
+
20
+ def info
21
+ output = if options[:website_only]
22
+ website
23
+ elsif options[:description_only]
24
+ description
25
+ else
26
+ description_and_website
27
+ end
28
+ output << "\n"
29
+ end
30
+
31
+ def should_insert?
32
+ !info.strip.empty? && !already_added_comment && !existing_comment_option
33
+ end
34
+
35
+ private
36
+
37
+ def already_added_comment
38
+ prev_line_comment && prev_line_comment.include?(comment)
39
+ end
40
+
41
+ # if there exists a prev_line_comment and the user has specified new_comments_only
42
+ def existing_comment_option
43
+ prev_line_comment && options[:new_comments_only]
44
+ end
45
+
46
+ def leading_spaces_count
47
+ original_line.length - original_line.lstrip.length
48
+ end
49
+
50
+ def description
51
+ "#{spec.summary}" if spec
52
+ end
53
+
54
+ def website
55
+ "#{spec.homepage.to_s}" if spec
56
+ end
57
+
58
+ def description_and_website
59
+ output = "#{description}"
60
+ output << " (#{website})" unless website.nil? || website.empty?
61
+ output
62
+ end
63
+
64
+ end
65
+ end
@@ -0,0 +1,46 @@
1
+ module AnnotateGem
2
+ class Gemfile
3
+
4
+ GEM_LINE_REGEX = /\A\s*gem[\s(]+["'](?<name>[^'"]*)["']/.freeze
5
+
6
+ attr_accessor :gemfile_path, :gem_lines, :source, :options
7
+
8
+ def initialize(gemfile_path, options = {})
9
+ @gemfile_path = gemfile_path
10
+ @source = []
11
+ @gem_lines = []
12
+ @options = options
13
+ end
14
+
15
+ def parse
16
+ self.source = File.readlines(gemfile_path)
17
+ source.each_with_index do |line, i|
18
+ if match = GEM_LINE_REGEX.match(line)
19
+ prev_line = source[i - 1] if i > 0
20
+ prev_line_comment = prev_line if is_line_a_comment?(prev_line)
21
+ self.gem_lines << GemLine.new(
22
+ name: match[:name],
23
+ original_line: line,
24
+ location: i,
25
+ prev_line_comment: prev_line_comment,
26
+ options: options
27
+ )
28
+ end
29
+ end
30
+ end
31
+
32
+ def write_comments
33
+ gem_lines.reverse.each do |gem_line|
34
+ source.insert(gem_line.location, gem_line.comment) if gem_line.should_insert?
35
+ end
36
+ File.write(gemfile_path, source.join)
37
+ end
38
+
39
+ private
40
+
41
+ def is_line_a_comment?(line)
42
+ line && line.strip.start_with?("#")
43
+ end
44
+
45
+ end
46
+ end
@@ -0,0 +1,66 @@
1
+ require "optparse"
2
+
3
+ module AnnotateGem
4
+ class Options
5
+
6
+ attr_accessor :options, :options_parser
7
+
8
+ def initialize
9
+ @options = {}
10
+ @options_parser = OptionParser.new do |opts|
11
+ add_banner(opts)
12
+ add_tail_options(opts)
13
+ add_info_options(opts)
14
+ add_gemfile_comment_options(opts)
15
+ end
16
+ end
17
+
18
+ def parse!(args)
19
+ options_parser.parse!(args)
20
+ validate_options
21
+ options
22
+ end
23
+
24
+ private
25
+
26
+ def validate_options
27
+ info_flags = options[:website_only] && options[:description_only]
28
+ raise ArgumentError, "Cannot set both --website-only and --description-only flags" if info_flags
29
+ end
30
+
31
+ def add_info_options(opts)
32
+ opts.on("--website-only", "Only output the website") do
33
+ options[:website_only] = true
34
+ end
35
+ opts.on("--description-only", "Only output the description") do
36
+ options[:description_only] = true
37
+ end
38
+ end
39
+
40
+ def add_gemfile_comment_options(opts)
41
+ opts.on("--new-comments-only", "Only add a comment to gemfile if there isn't a comment already") do
42
+ options[:new_comments_only] = true
43
+ end
44
+ end
45
+
46
+ def add_banner(opts)
47
+ opts.banner = <<-BANNER.gsub(/\A\s{8}/, '')
48
+ #{AnnotateGem::DESCRIPTION}
49
+ Usage: #{opts.program_name} [options]
50
+ #{opts.program_name} [gem name]
51
+ BANNER
52
+ end
53
+
54
+ def add_tail_options(opts)
55
+ opts.on_tail("-h", "--help", "Show this message") do
56
+ puts opts
57
+ exit
58
+ end
59
+ opts.on_tail("-v", "--version", "Show version") do
60
+ puts AnnotateGem::VERSION
61
+ exit
62
+ end
63
+ end
64
+
65
+ end
66
+ end
@@ -0,0 +1,43 @@
1
+ module AnnotateGem
2
+ module SpecFinder
3
+ extend self
4
+
5
+ def find_specs_for(gem_lines, &block)
6
+ gem_lines = Array(gem_lines)
7
+ find_matching_specs_for(gem_lines)
8
+ gems_to_fetch = gem_lines.select { |gem_line| gem_line.spec.nil? }
9
+ fetch_specs_for(gems_to_fetch, &block) if gems_to_fetch.any?
10
+ end
11
+
12
+ def find_matching_specs_for(gem_lines)
13
+ gem_lines.each do |line|
14
+ matching_specs = Gem::Dependency.new(line.name).matching_specs
15
+ # TODO: need to find latest
16
+ line.spec = matching_specs.first if matching_specs.any?
17
+ end
18
+ end
19
+
20
+ def fetch_specs_for(gem_lines)
21
+ total = gem_lines.length
22
+ processing = 0
23
+ yield processing, total if block_given?
24
+ # TODO: Support private sources
25
+ remote = Bundler::Source::Rubygems::Remote.new(Gem.sources.first.uri)
26
+ fetcher = Bundler::Fetcher.new(remote)
27
+ dependency_fetcher = fetcher.fetchers.find {|f| Bundler::Fetcher::Dependency === f }
28
+ versions, _ = dependency_fetcher.dependency_specs(gem_lines.collect(&:name))
29
+ gem_lines.each do |gem_line|
30
+ processing += 1
31
+ yield processing, total if block_given?
32
+ gem_versions = versions.select { |v| v.first == gem_line.name }
33
+ next if gem_versions.empty? # couldn't find version on RubyGems so go to next one
34
+ version = find_latest_version(gem_versions)
35
+ gem_line.spec = fetcher.fetch_spec([gem_line.name, version])
36
+ end
37
+ end
38
+
39
+ def find_latest_version(versions)
40
+ versions.sort_by { |v| v[1] }.last[1]
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,4 @@
1
+ module AnnotateGem
2
+ VERSION = "0.0.8".freeze
3
+ DESCRIPTION = "Add comments to your Gemfile with each dependency's description.".freeze
4
+ end
@@ -0,0 +1,23 @@
1
+ require "test_helper"
2
+ require "annotate_gem/cli"
3
+
4
+ # Acts as integration test since it will actually fetch data from API
5
+ class AnnotateGem::CLITest < Minitest::Test
6
+
7
+ def test_run_for_gemfile
8
+ with_gemfile(File.read(gemfile_path)) do |path|
9
+ Bundler.expects(:default_gemfile).returns(path)
10
+ out, _ = capture_io do
11
+ AnnotateGem::CLI.new.run_for_gemfile
12
+ end
13
+ assert_equal File.read(annotated_gemfile_path), File.read(path)
14
+ end
15
+ end
16
+
17
+ def test_run_for_gem
18
+ out, _ = capture_io do
19
+ AnnotateGem::CLI.new.run_for_gem("annotate_gem")
20
+ end
21
+ assert_equal "Add comments to your Gemfile with each dependency's description. (https://github.com/ivantsepp/annotate_gem)\n", out
22
+ end
23
+ end
@@ -0,0 +1,79 @@
1
+ require "test_helper"
2
+
3
+ class AnnotateGem::GemLineTest < Minitest::Test
4
+
5
+ def test_info
6
+ gem_line = create_gem_line
7
+ spec = stub(summary: "Hello world", homepage: "http://example.com")
8
+ gem_line.spec = spec
9
+ assert_equal "Hello world (http://example.com)\n", gem_line.info
10
+ end
11
+
12
+ def test_info_with_website_only
13
+ gem_line = create_gem_line(options: { website_only: true })
14
+ spec = stub(summary: "Hello world", homepage: "http://example.com")
15
+ gem_line.spec = spec
16
+ assert_equal "http://example.com\n", gem_line.info
17
+ end
18
+
19
+ def test_info_with_description_only
20
+ gem_line = create_gem_line(options: { description_only: true })
21
+ spec = stub(summary: "Hello world", homepage: "http://example.com")
22
+ gem_line.spec = spec
23
+ assert_equal "Hello world\n", gem_line.info
24
+ end
25
+
26
+ def test_should_insert_with_no_info
27
+ gem_line = create_gem_line
28
+ gem_line.expects(:info).returns("")
29
+ refute gem_line.should_insert?
30
+ end
31
+
32
+ def test_should_insert_with_no_spec
33
+ gem_line = create_gem_line
34
+ refute gem_line.should_insert?
35
+ end
36
+
37
+ def test_should_insert_with_already_added_comment
38
+ gem_line = create_gem_line(prev_line_comment: "# Hello world (http://example.com)\n")
39
+ spec = stub(summary: "Hello world", homepage: "http://example.com")
40
+ gem_line.spec = spec
41
+ refute gem_line.should_insert?
42
+ end
43
+
44
+ def test_should_insert_with_new_comments_only
45
+ gem_line = create_gem_line(
46
+ prev_line_comment: "# This is an existing comment\n",
47
+ options: { new_comments_only: true }
48
+ )
49
+ spec = stub(summary: "Hello world", homepage: "http://example.com")
50
+ gem_line.spec = spec
51
+ refute gem_line.should_insert?
52
+ end
53
+
54
+ def test_comment
55
+ gem_line = create_gem_line
56
+ spec = stub(summary: "Hello world", homepage: "http://example.com")
57
+ gem_line.spec = spec
58
+ assert_equal "# Hello world (http://example.com)\n", gem_line.comment
59
+ end
60
+
61
+ def test_comment_with_indentation_in_original_line
62
+ gem_line = AnnotateGem::GemLine.new(
63
+ name: "annotate_gem",
64
+ original_line: " \tgem 'annotate_gem'"
65
+ )
66
+ spec = stub(summary: "Hello world", homepage: "http://example.com")
67
+ gem_line.spec = spec
68
+ assert_equal " \t# Hello world (http://example.com)\n", gem_line.comment
69
+ end
70
+
71
+ private
72
+
73
+ def create_gem_line(options = {})
74
+ AnnotateGem::GemLine.new(
75
+ { name: "annotate_gem", original_line: "gem 'annotate_gem'" }.merge(options)
76
+ )
77
+ end
78
+
79
+ end
@@ -0,0 +1,71 @@
1
+ require "test_helper"
2
+
3
+ class AnnotateGem::GemfileTest < Minitest::Test
4
+
5
+ def test_parses_source
6
+ gemfile = gemfile_for(unindent(<<-GEMFILE))
7
+ hello
8
+ world!
9
+ GEMFILE
10
+ assert 2, gemfile.source.length
11
+ assert_equal "hello\n", gemfile.source.first
12
+ assert_equal "world!\n", gemfile.source.last
13
+ end
14
+
15
+ def test_parses_gem_lines
16
+ AnnotateGem::GemLine.expects(:new).with(
17
+ name: "rails",
18
+ original_line: "gem \"rails\"\n",
19
+ location: 0,
20
+ prev_line_comment: nil,
21
+ options: {}
22
+ ).once
23
+ AnnotateGem::GemLine.expects(:new).with(
24
+ name: "annotate_gem",
25
+ original_line: "gem \"annotate_gem\"\n",
26
+ location: 2,
27
+ prev_line_comment: "# this gem has a comment\n",
28
+ options: {}
29
+ ).once
30
+ gemfile = gemfile_for(unindent(<<-GEMFILE))
31
+ gem "rails"
32
+ # this gem has a comment
33
+ gem "annotate_gem"
34
+ # gem "commented_out"
35
+ GEMFILE
36
+ assert_equal 2, gemfile.gem_lines.length
37
+ end
38
+
39
+ def test_write_comments
40
+ with_gemfile("gem 'rails'") do |path|
41
+ gemfile = AnnotateGem::Gemfile.new(path)
42
+ gemfile.gem_lines = [mock(location: 0, comment: "Rails description!\n", should_insert?: true)]
43
+ gemfile.source = ["gem 'rails'"]
44
+ gemfile.write_comments
45
+ assert_equal "Rails description!\ngem 'rails'", File.read(path)
46
+ end
47
+ end
48
+
49
+ def test_that_options_are_passed_through
50
+ AnnotateGem::GemLine.expects(:new).with(
51
+ name: "rails",
52
+ original_line: "gem 'rails'",
53
+ location: 0,
54
+ prev_line_comment: nil,
55
+ options: { description_only: true }
56
+ ).once
57
+ gemfile = gemfile_for("gem 'rails'", description_only: true)
58
+ end
59
+
60
+ private
61
+
62
+ def gemfile_for(content, options = {})
63
+ gemfile = nil
64
+ with_gemfile(content) do |path|
65
+ gemfile = AnnotateGem::Gemfile.new(path, options)
66
+ gemfile.parse
67
+ end
68
+ gemfile
69
+ end
70
+
71
+ end
@@ -0,0 +1,79 @@
1
+ require "test_helper"
2
+
3
+ class AnnotateGem::SpecFinderTest < Minitest::Test
4
+ def test_find_specs_for
5
+ gem_line_1 = mock(spec: nil)
6
+ gem_line_2 = mock(spec: "spec")
7
+ AnnotateGem::SpecFinder.expects(:find_matching_specs_for).with([gem_line_1, gem_line_2])
8
+ AnnotateGem::SpecFinder.expects(:fetch_specs_for).with([gem_line_1])
9
+ AnnotateGem::SpecFinder.find_specs_for([gem_line_1, gem_line_2])
10
+ end
11
+
12
+ def test_find_matching_specs_for
13
+ spec_1 = mock
14
+ gem_line_1 = mock(name: "1")
15
+ gem_line_1.expects(:spec=).with(spec_1)
16
+ spec_2 = mock
17
+ gem_line_2 = mock(name: "2")
18
+ gem_line_2.expects(:spec=).with(spec_2)
19
+ gem_lines = [gem_line_1, gem_line_2]
20
+ Gem::Dependency.expects(:new).with("1").returns(mock(matching_specs: [spec_1]))
21
+ Gem::Dependency.expects(:new).with("2").returns(mock(matching_specs: [spec_2]))
22
+ AnnotateGem::SpecFinder.find_matching_specs_for(gem_lines)
23
+ end
24
+
25
+ def test_fetch_specs_for
26
+ original_stdout = $stdout
27
+ $stdout = StringIO.new
28
+
29
+ spec_1 = mock
30
+ gem_line_1 = mock
31
+ gem_line_1.stubs(name: "1")
32
+ gem_line_1.expects(:spec=).with(spec_1)
33
+ spec_2 = mock
34
+ gem_line_2 = mock
35
+ gem_line_2.stubs(name: "2")
36
+ gem_line_2.expects(:spec=).with(spec_2)
37
+
38
+ dependency_fetcher_mock = Bundler::Fetcher::Dependency.new(nil, nil, nil)
39
+ Bundler::Fetcher.any_instance.expects(:fetchers).returns([dependency_fetcher_mock])
40
+ dependency_fetcher_mock.expects(:dependency_specs).with(["1", "2"]).returns([[
41
+ ["1", Gem::Version.new("1")],
42
+ ["2", Gem::Version.new("1")],
43
+ ], "dependencies here"])
44
+ AnnotateGem::SpecFinder.expects(:find_latest_version).returns(Gem::Version.new("1")).twice
45
+ Bundler::Fetcher.any_instance.expects(:fetch_spec).with(["1", Gem::Version.new("1")]).returns(spec_1)
46
+ Bundler::Fetcher.any_instance.expects(:fetch_spec).with(["2", Gem::Version.new("1")]).returns(spec_2)
47
+ yielded_values = []
48
+ AnnotateGem::SpecFinder.fetch_specs_for([gem_line_1, gem_line_2]) do |*args|
49
+ yielded_values << args
50
+ end
51
+ assert_equal [[0, 2], [1, 2], [2, 2]], yielded_values
52
+ $stdout = original_stdout
53
+ end
54
+
55
+ def test_fetch_unknown_specs
56
+ original_stdout = $stdout
57
+ $stdout = StringIO.new
58
+
59
+ gem_line_1 = mock
60
+ gem_line_1.stubs(name: "1")
61
+ gem_line_1.expects(:spec=).never
62
+
63
+ dependency_fetcher_mock = Bundler::Fetcher::Dependency.new(nil, nil, nil)
64
+ Bundler::Fetcher.any_instance.expects(:fetchers).returns([dependency_fetcher_mock])
65
+ dependency_fetcher_mock.expects(:dependency_specs).with(["1"]).returns([[], "dependencies here"])
66
+ Bundler::Fetcher.any_instance.expects(:fetch_spec).never
67
+ AnnotateGem::SpecFinder.fetch_specs_for([gem_line_1])
68
+
69
+ $stdout = original_stdout
70
+ end
71
+
72
+ def test_find_latest_version
73
+ versions = [
74
+ ["rails", Gem::Version.new("2.3.5")],
75
+ ["rails", Gem::Version.new("4")]
76
+ ]
77
+ assert_equal Gem::Version.new("4"), AnnotateGem::SpecFinder.find_latest_version(versions)
78
+ end
79
+ end
@@ -0,0 +1,31 @@
1
+ source "https://rubygems.org"
2
+
3
+ gem 'rails', '4.2.1'
4
+ gem 'sqlite3'
5
+ gem 'sass-rails', '~> 5.0'
6
+ gem 'uglifier', '>= 1.3.0'
7
+ gem 'coffee-rails', '~> 4.1.0'
8
+ # See https://github.com/rails/execjs#readme for more supported runtimes
9
+ # gem 'therubyracer', platforms: :ruby
10
+
11
+ gem 'jquery-rails'
12
+ gem 'turbolinks'
13
+ gem 'jbuilder', '~> 2.0'
14
+ # bundle exec rake doc:rails generates the API under doc/api.
15
+ gem 'sdoc', '~> 0.4.0', group: :doc
16
+
17
+ # Use ActiveModel has_secure_password
18
+ # gem 'bcrypt', '~> 3.1.7'
19
+
20
+ # Use Unicorn as the app server
21
+ # gem 'unicorn'
22
+
23
+ # Use Capistrano for deployment
24
+ # gem 'capistrano-rails', group: :development
25
+
26
+ group :development, :test do
27
+ gem 'byebug'
28
+ gem 'web-console', '~> 2.0'
29
+ # Spring speeds up development by keeping your application running in the background. Read more: https://github.com/rails/spring
30
+ gem 'spring'
31
+ end
@@ -0,0 +1,43 @@
1
+ source "https://rubygems.org"
2
+
3
+ # Full-stack web application framework. (http://rubyonrails.org)
4
+ gem 'rails', '4.2.1'
5
+ # This module allows Ruby programs to interface with the SQLite3 database engine (http://www.sqlite.org) (https://github.com/sparklemotion/sqlite3-ruby)
6
+ gem 'sqlite3'
7
+ # Sass adapter for the Rails asset pipeline. (https://github.com/rails/sass-rails)
8
+ gem 'sass-rails', '~> 5.0'
9
+ # Ruby wrapper for UglifyJS JavaScript compressor (http://github.com/lautis/uglifier)
10
+ gem 'uglifier', '>= 1.3.0'
11
+ # CoffeeScript adapter for the Rails asset pipeline. (https://github.com/rails/coffee-rails)
12
+ gem 'coffee-rails', '~> 4.1.0'
13
+ # See https://github.com/rails/execjs#readme for more supported runtimes
14
+ # gem 'therubyracer', platforms: :ruby
15
+
16
+ # Use jQuery with Rails 4+ (http://rubygems.org/gems/jquery-rails)
17
+ gem 'jquery-rails'
18
+ # Turbolinks makes navigating your web application faster (https://github.com/turbolinks/turbolinks-rails)
19
+ gem 'turbolinks'
20
+ # Create JSON structures via a Builder-style DSL (https://github.com/rails/jbuilder)
21
+ gem 'jbuilder', '~> 2.0'
22
+ # bundle exec rake doc:rails generates the API under doc/api.
23
+ # rdoc html with javascript search index. (http://github.com/voloko/sdoc)
24
+ gem 'sdoc', '~> 0.4.0', group: :doc
25
+
26
+ # Use ActiveModel has_secure_password
27
+ # gem 'bcrypt', '~> 3.1.7'
28
+
29
+ # Use Unicorn as the app server
30
+ # gem 'unicorn'
31
+
32
+ # Use Capistrano for deployment
33
+ # gem 'capistrano-rails', group: :development
34
+
35
+ group :development, :test do
36
+ # Ruby 2.0 fast debugger - base + CLI (http://github.com/deivid-rodriguez/byebug)
37
+ gem 'byebug'
38
+ # A debugging tool for your Ruby on Rails applications. (https://github.com/rails/web-console)
39
+ gem 'web-console', '~> 2.0'
40
+ # Spring speeds up development by keeping your application running in the background. Read more: https://github.com/rails/spring
41
+ # Rails application preloader (https://github.com/rails/spring)
42
+ gem 'spring'
43
+ end
@@ -0,0 +1,31 @@
1
+ require "minitest/autorun"
2
+ require "mocha/mini_test"
3
+ require "annotate_gem"
4
+
5
+ module TestHelpers
6
+
7
+ def gemfile_path
8
+ File.join(File.dirname(__FILE__), "fixtures", "Gemfile")
9
+ end
10
+
11
+ def annotated_gemfile_path
12
+ File.join(File.dirname(__FILE__), "fixtures", "Gemfile_annotated")
13
+ end
14
+
15
+ def with_gemfile(content)
16
+ file = Tempfile.new('gemfile')
17
+ file.write(content)
18
+ file.close
19
+ yield(file.path)
20
+ file.unlink
21
+ end
22
+
23
+ def unindent(str)
24
+ str.gsub(/^#{str.scan(/^[ ]+(?=\S)/).min}/, "")
25
+ end
26
+
27
+ end
28
+
29
+ class Minitest::Test
30
+ include TestHelpers
31
+ end
metadata ADDED
@@ -0,0 +1,130 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: annotate_gem
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.8
5
+ platform: ruby
6
+ authors:
7
+ - Ivan Tse
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2016-04-30 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bundler
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: 1.11.2
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: 1.11.2
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '10.0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '10.0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: minitest
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '5.0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '5.0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: mocha
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '1.1'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '1.1'
69
+ description: 'Clarify your dependencies by adding a detailed comment to each line
70
+ in Gemfile specifying the gem''s summary and its website if any. '
71
+ email:
72
+ - ivan.tse1@gmail.com
73
+ executables:
74
+ - annotate_gem
75
+ extensions: []
76
+ extra_rdoc_files: []
77
+ files:
78
+ - ".gitignore"
79
+ - Gemfile
80
+ - LICENSE.txt
81
+ - README.md
82
+ - Rakefile
83
+ - annotate_gem.gemspec
84
+ - bin/annotate_gem
85
+ - lib/annotate_gem.rb
86
+ - lib/annotate_gem/cli.rb
87
+ - lib/annotate_gem/gem_line.rb
88
+ - lib/annotate_gem/gemfile.rb
89
+ - lib/annotate_gem/options.rb
90
+ - lib/annotate_gem/spec_finder.rb
91
+ - lib/annotate_gem/version.rb
92
+ - test/annotate_gem/cli_test.rb
93
+ - test/annotate_gem/gem_line_test.rb
94
+ - test/annotate_gem/gemfile_test.rb
95
+ - test/annotate_gem/spec_finder_test.rb
96
+ - test/fixtures/Gemfile
97
+ - test/fixtures/Gemfile_annotated
98
+ - test/test_helper.rb
99
+ homepage: https://github.com/ivantsepp/annotate_gem
100
+ licenses:
101
+ - MIT
102
+ metadata: {}
103
+ post_install_message:
104
+ rdoc_options: []
105
+ require_paths:
106
+ - lib
107
+ required_ruby_version: !ruby/object:Gem::Requirement
108
+ requirements:
109
+ - - ">="
110
+ - !ruby/object:Gem::Version
111
+ version: '0'
112
+ required_rubygems_version: !ruby/object:Gem::Requirement
113
+ requirements:
114
+ - - ">="
115
+ - !ruby/object:Gem::Version
116
+ version: '0'
117
+ requirements: []
118
+ rubyforge_project:
119
+ rubygems_version: 2.6.3
120
+ signing_key:
121
+ specification_version: 4
122
+ summary: Add comments to your Gemfile with each dependency's description.
123
+ test_files:
124
+ - test/annotate_gem/cli_test.rb
125
+ - test/annotate_gem/gem_line_test.rb
126
+ - test/annotate_gem/gemfile_test.rb
127
+ - test/annotate_gem/spec_finder_test.rb
128
+ - test/fixtures/Gemfile
129
+ - test/fixtures/Gemfile_annotated
130
+ - test/test_helper.rb