unbundler 0.0.1

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,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in unbundler.gemspec
4
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,13 @@
1
+ DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
2
+ Version 2, December 2004
3
+
4
+ Copyright (C) 2004 Sam Hocevar <sam@hocevar.net>
5
+
6
+ Everyone is permitted to copy and distribute verbatim or modified
7
+ copies of this license document, and changing it is allowed as long
8
+ as the name is changed.
9
+
10
+ DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
11
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
12
+
13
+ 0. You just DO WHAT THE FUCK YOU WANT TO.
data/README.md ADDED
@@ -0,0 +1,32 @@
1
+ # Unbundler
2
+
3
+ Remove gems installed by bundler
4
+
5
+ ## Installation
6
+
7
+ Add this line to your application's Gemfile:
8
+
9
+ gem 'unbundler'
10
+
11
+ And then execute:
12
+
13
+ $ bundle
14
+
15
+ Or install it yourself as:
16
+
17
+ $ gem install unbundler
18
+
19
+ ## Usage
20
+
21
+ `unbundle` - uninstall all gems installed by current bundle except gems in global keep list
22
+ `unbundle --keep gem1` - uninstall all gems except gem1 and gems in global keep list
23
+ `unbundle show` or `unbundle list` - show list of gems to be unbundled
24
+ `unbundle edit_keep_list` - open global keep list in default editor
25
+
26
+ ## Contributing
27
+
28
+ 1. Fork it
29
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
30
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
31
+ 4. Push to the branch (`git push origin my-new-feature`)
32
+ 5. Create new Pull Request
data/Rakefile ADDED
@@ -0,0 +1,6 @@
1
+ require "bundler/gem_tasks"
2
+ require 'rspec/core/rake_task'
3
+
4
+ RSpec::Core::RakeTask.new(:spec)
5
+
6
+ task :default => :spec
data/bin/unbundle ADDED
@@ -0,0 +1,6 @@
1
+ #!/usr/bin/env ruby
2
+ # Exit cleanly from an early interrupt
3
+ Signal.trap("INT") { exit 1 }
4
+
5
+ require 'unbundler'
6
+ Unbundler::CLI.start
data/bin/unbundler ADDED
@@ -0,0 +1,5 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'unbundler'
4
+ bin = "#{File.dirname(__FILE__)}/unbundle #{ARGV.join(" ")}"
5
+ exec bin
@@ -0,0 +1,87 @@
1
+ require 'trollop'
2
+ require 'unbundler/gem_list'
3
+ require 'pp'
4
+
5
+ module Unbundler
6
+ class CLI
7
+ def self.start
8
+ cli = CLI.new
9
+ cli.run(cli.parse_args)
10
+ end
11
+
12
+ def run(opts)
13
+ @interactive = opts[:interactive]
14
+ @plain = opts[:plain]
15
+ @quiet = opts[:quiet]
16
+ @gems = GemList.new(opts[:keep])
17
+ self.send(opts[:action])
18
+ end
19
+
20
+ def parse_args
21
+ opts = { :action => :unbundle }
22
+ case ARGV.first
23
+ when "show", "list"
24
+ opts[:action] = :show
25
+ when "edit_keep_list"
26
+ opts[:action] = :edit_keep_list
27
+ end
28
+ opts.merge( Trollop::options do
29
+ version "unbundler v#{Unbundler::VERSION}"
30
+ opt :keep, "List of gems to keep", :type => :strings
31
+ opt :plain, "Plain output for unbundle list"
32
+ opt :interactive, "Interactive unbundle(ask about each gem)"
33
+ opt :quiet, "Produce no output"
34
+ end)
35
+ end
36
+
37
+ private
38
+
39
+ def unbundle
40
+ @gems.each do |gem|
41
+ uninstall_gem(gem) unless keep(gem)
42
+ end
43
+ end
44
+
45
+ def show
46
+ puts "Gems to be unbundled:" unless @plain
47
+ @gems.each do |gem|
48
+ puts @plain ? gem : " * #{gem}"
49
+ end
50
+ end
51
+
52
+ def edit_keep_list
53
+ exec "${FCEDIT:-${VISUAL:-${EDITOR:-vi}}} ~/.unbundler_keep"
54
+ end
55
+
56
+ # http://stackoverflow.com/a/14527475/162459
57
+ def get_char
58
+ state = `stty -g`
59
+ `stty raw -echo -icanon isig`
60
+ STDIN.getc.chr
61
+ ensure
62
+ `stty #{state}`
63
+ end
64
+
65
+ def keep(gem)
66
+ return false unless @interactive
67
+ while true do
68
+ puts "Delete #{gem} (y/n/a)"
69
+ case get_char
70
+ when 'y', 'Y'
71
+ return false
72
+ when 'n', 'N'
73
+ return true
74
+ when 'a', 'A'
75
+ @interactive = false
76
+ return false
77
+ else
78
+ puts "y/n/a expected"
79
+ end
80
+ end
81
+ end
82
+
83
+ def uninstall_gem(gem)
84
+ `gem -x uninstall #{gem}`
85
+ end
86
+ end
87
+ end
@@ -0,0 +1,52 @@
1
+ require 'unbundler/keep_list'
2
+ require 'bundler'
3
+
4
+ module Unbundler
5
+ class GemList
6
+ def initialize(keep_list)
7
+ @keep_list = KeepList.new(keep_list || [])
8
+ @global_keep_list = KeepList.new(global_keep_list)
9
+ end
10
+
11
+ def each
12
+ gems_to_unbundle.each do |gem|
13
+ yield gem.name
14
+ end
15
+ end
16
+
17
+ private
18
+
19
+ def unbundler_runtime_dependencies
20
+ Gem::Dependency.new("unbundler").to_spec.runtime_dependencies
21
+ end
22
+
23
+ def create_default_keep_list
24
+ keep_list_file = File.expand_path("~/.unbundler_keep")
25
+ File.open(keep_list_file, "w") do |keep_list|
26
+ keep_list.puts "unbundler"
27
+ unbundler_runtime_dependencies.each do |gem|
28
+ keep_list.puts "#{gem.name} '#{gem.requirement.to_s}'"
29
+ end
30
+ end
31
+ end
32
+
33
+ def global_keep_list
34
+ keep_list_file = File.expand_path("~/.unbundler_keep")
35
+ create_default_keep_list unless File.exist?(keep_list_file)
36
+ File.open(keep_list_file).readlines.map(&:chomp).map(&:strip)
37
+ end
38
+
39
+ def in_keep_list?(gem)
40
+ @keep_list.include?(gem) || @global_keep_list.include?(gem)
41
+ end
42
+
43
+ def bundled_gems
44
+ @bundled_gems ||= Bundler.load.specs
45
+ end
46
+
47
+
48
+ def gems_to_unbundle
49
+ @gems_to_unbundle ||= bundled_gems.reject { |gem| in_keep_list?(gem) }
50
+ end
51
+ end
52
+ end
@@ -0,0 +1,20 @@
1
+ require 'rubygems'
2
+
3
+ module Unbundler
4
+ class KeepList
5
+ def initialize(gems_list)
6
+ name_version_pairs = gems_list.map do |gem|
7
+ gem = gem.tr("\"'", "")
8
+ pair = gem.split(" ", 2)
9
+ [pair.shift, Gem::Dependency.new('unbundler', pair.shift)]
10
+ end
11
+ @keep_list = Hash[name_version_pairs]
12
+ end
13
+
14
+ def include?(gem)
15
+ return false unless @keep_list.keys.include?(gem.name)
16
+ return false unless @keep_list[gem.name].match?('unbundler', gem.version)
17
+ true
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,3 @@
1
+ module Unbundler
2
+ VERSION = "0.0.1"
3
+ end
data/lib/unbundler.rb ADDED
@@ -0,0 +1,3 @@
1
+ require "unbundler/version"
2
+ require "unbundler/cli"
3
+
data/spec/cli_spec.rb ADDED
@@ -0,0 +1,83 @@
1
+ require 'unbundler'
2
+ require 'spec_helper'
3
+
4
+ describe Unbundler::CLI do
5
+ def replace_argv(new_argv)
6
+ ::Object.send(:remove_const, :ARGV) # suppress const redefinition warning
7
+ ::Object.send(:const_set, :ARGV, Array(new_argv))
8
+ end
9
+
10
+ def run_cli(args=[])
11
+ replace_argv(args)
12
+ subject.run(subject.parse_args)
13
+ return 0
14
+ rescue SystemExit => e
15
+ return e.status
16
+ end
17
+
18
+ shared_examples_for 'command line argument' do
19
+ it 'short form' do
20
+ replace_argv([short_name] | Array(value))
21
+ subject.parse_args[key].should == expected_value
22
+ end
23
+ it 'long form' do
24
+ replace_argv([long_name] | Array(value))
25
+ subject.parse_args[key] == value
26
+ end
27
+ it 'short and long form should match' do
28
+ replace_argv([short_name] | Array(value))
29
+ opts = subject.parse_args
30
+ replace_argv([long_name] | Array(value))
31
+ opts[key].should == subject.parse_args[key]
32
+ end
33
+ end
34
+
35
+ context 'keep option' do
36
+ let(:short_name) {'-k'}
37
+ let(:long_name) {'--keep'}
38
+ let(:key) {:keep}
39
+ let(:value) {%w(gem1 gem2 gem3)}
40
+ let(:expected_value){%w(gem1 gem2 gem3)}
41
+ it_should_behave_like 'command line argument'
42
+ end
43
+
44
+ context 'plain option' do
45
+ let(:short_name) {'-p'}
46
+ let(:long_name) {'--plain'}
47
+ let(:key) {:plain}
48
+ let(:value) {''}
49
+ let(:expected_value){true}
50
+ it_should_behave_like 'command line argument'
51
+ end
52
+
53
+ context 'interactive option' do
54
+ let(:short_name) {'-i'}
55
+ let(:long_name) {'--interactive'}
56
+ let(:key) {:interactive}
57
+ let(:value) {''}
58
+ let(:expected_value){true}
59
+ it_should_behave_like 'command line argument'
60
+ end
61
+
62
+ context 'quiet option' do
63
+ let(:short_name) {'-q'}
64
+ let(:long_name) {'--quiet'}
65
+ let(:key) {:quiet}
66
+ let(:value) {''}
67
+ let(:expected_value){true}
68
+ it_should_behave_like 'command line argument'
69
+ end
70
+
71
+ it 'should run action specified in command line' do
72
+ ['show', 'edit_keep_list'].each do |action|
73
+ subject.should_receive(action.to_sym).and_return(true)
74
+ run_cli(action)
75
+ end
76
+ end
77
+
78
+ it 'should run unbundle action by default(i.e. no action is specified)' do
79
+ subject.should_receive(:unbundle).and_return(true)
80
+ run_cli
81
+ end
82
+
83
+ end
@@ -0,0 +1,42 @@
1
+ require 'unbundler'
2
+ require 'unbundler/gem_list'
3
+ require 'spec_helper'
4
+
5
+ describe Unbundler::GemList do
6
+ subject { lambda { |keep_list=nil| Unbundler::GemList.new(keep_list || []) } }
7
+ let(:specs) { [Gem::Specification.new("gem1"),
8
+ Gem::Specification.new("gem2"),
9
+ Gem::Specification.new("gem3"),
10
+ Gem::Specification.new("gem4"),
11
+ Gem::Specification.new("gem5"),
12
+ Gem::Specification.new("gem6")] }
13
+ before(:each) do
14
+ bundler_load = double("Bundler.load")
15
+ bundler_load.should_receive(:specs).and_return(specs)
16
+ Bundler.should_receive(:load).and_return(bundler_load)
17
+ end
18
+
19
+ it 'should allow to enumarate gems to unbundle' do
20
+ gems = []
21
+ subject.call.each { |gem| gems << gem }
22
+ gems.should =~ specs.map { |spec| spec.name }
23
+ end
24
+
25
+ it 'should exclude gems from global keep list' do
26
+ file = double(file)
27
+ keep_list_file = File.expand_path("~/.unbundler_keep")
28
+ File.should_receive(:exist?).with(keep_list_file).and_return(true)
29
+ File.should_receive(:open).with(keep_list_file).and_return(file)
30
+ file.should_receive(:readlines).and_return(["gem3"])
31
+ gems = []
32
+ subject.call.each { |gem| gems << gem }
33
+ gems.should_not include "gem3"
34
+ end
35
+
36
+ it 'should exclude gems from provided keep list' do
37
+ gems = []
38
+ keep_list = %w(gem2 gem4 gem6)
39
+ subject.call(keep_list).each { |gem| gems << gem }
40
+ expect(gems).not_to match_array keep_list
41
+ end
42
+ end
@@ -0,0 +1,19 @@
1
+ require 'unbundler'
2
+ require 'unbundler/keep_list'
3
+ require 'spec_helper'
4
+
5
+ describe Unbundler::KeepList do
6
+ subject { lambda { |gem_list| Unbundler::KeepList.new(gem_list) } }
7
+
8
+ it 'should check gem presence by gem name' do
9
+ gem = Gem::Specification.new("gem")
10
+ expect {subject.call(%w(gem gem2 gem3)).include?(gem)}.to be_true
11
+ end
12
+
13
+ it 'should check gem presence by gem name and version' do
14
+ gem = Gem::Specification.new("gem", "1.0.0")
15
+ gems = %(gem1 gem3 gem3)
16
+ gems << "gem '1.0.0'"
17
+ expect {subject.call(gems).include?(gem)}.to be_true
18
+ end
19
+ end
@@ -0,0 +1,10 @@
1
+ RSpec.configure do |config|
2
+ # Use color in STDOUT
3
+ config.color_enabled = true
4
+
5
+ # Use color not only in STDOUT but also in pagers and files
6
+ config.tty = true
7
+
8
+ # Use the specified formatter
9
+ config.formatter = :documentation # :progress, :html, :textmate
10
+ end
data/unbundler.gemspec ADDED
@@ -0,0 +1,26 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'unbundler/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "unbundler"
8
+ spec.version = Unbundler::VERSION
9
+ spec.authors = ["Stas Turlo"]
10
+ spec.email = ["stanislav.turlo@rightscale.com"]
11
+ spec.description = %q{Remove gems installed by bundler}
12
+ spec.summary = %q{Remove gems installed by bundler}
13
+ spec.homepage = ""
14
+ spec.license = "WTFPL"
15
+
16
+ spec.files = `git ls-files`.split($/)
17
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
+ spec.require_paths = ["lib"]
20
+
21
+ spec.add_development_dependency "rake"
22
+ spec.add_development_dependency "rspec", ">= 2.0.0"
23
+
24
+ spec.add_dependency "bundler"
25
+ spec.add_dependency "trollop"
26
+ end
metadata ADDED
@@ -0,0 +1,139 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: unbundler
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Stas Turlo
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2014-01-26 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: rake
16
+ requirement: !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ! '>='
20
+ - !ruby/object:Gem::Version
21
+ version: '0'
22
+ type: :development
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: rspec
32
+ requirement: !ruby/object:Gem::Requirement
33
+ none: false
34
+ requirements:
35
+ - - ! '>='
36
+ - !ruby/object:Gem::Version
37
+ version: 2.0.0
38
+ type: :development
39
+ prerelease: false
40
+ version_requirements: !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ! '>='
44
+ - !ruby/object:Gem::Version
45
+ version: 2.0.0
46
+ - !ruby/object:Gem::Dependency
47
+ name: bundler
48
+ requirement: !ruby/object:Gem::Requirement
49
+ none: false
50
+ requirements:
51
+ - - ! '>='
52
+ - !ruby/object:Gem::Version
53
+ version: '0'
54
+ type: :runtime
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
+ - !ruby/object:Gem::Dependency
63
+ name: trollop
64
+ requirement: !ruby/object:Gem::Requirement
65
+ none: false
66
+ requirements:
67
+ - - ! '>='
68
+ - !ruby/object:Gem::Version
69
+ version: '0'
70
+ type: :runtime
71
+ prerelease: false
72
+ version_requirements: !ruby/object:Gem::Requirement
73
+ none: false
74
+ requirements:
75
+ - - ! '>='
76
+ - !ruby/object:Gem::Version
77
+ version: '0'
78
+ description: Remove gems installed by bundler
79
+ email:
80
+ - stanislav.turlo@rightscale.com
81
+ executables:
82
+ - unbundle
83
+ - unbundler
84
+ extensions: []
85
+ extra_rdoc_files: []
86
+ files:
87
+ - .gitignore
88
+ - Gemfile
89
+ - LICENSE.txt
90
+ - README.md
91
+ - Rakefile
92
+ - bin/unbundle
93
+ - bin/unbundler
94
+ - lib/unbundler.rb
95
+ - lib/unbundler/cli.rb
96
+ - lib/unbundler/gem_list.rb
97
+ - lib/unbundler/keep_list.rb
98
+ - lib/unbundler/version.rb
99
+ - spec/cli_spec.rb
100
+ - spec/gem_list_spec.rb
101
+ - spec/keep_list_spec.rb
102
+ - spec/spec_helper.rb
103
+ - unbundler.gemspec
104
+ homepage: ''
105
+ licenses:
106
+ - WTFPL
107
+ post_install_message:
108
+ rdoc_options: []
109
+ require_paths:
110
+ - lib
111
+ required_ruby_version: !ruby/object:Gem::Requirement
112
+ none: false
113
+ requirements:
114
+ - - ! '>='
115
+ - !ruby/object:Gem::Version
116
+ version: '0'
117
+ segments:
118
+ - 0
119
+ hash: -3134477564524655065
120
+ required_rubygems_version: !ruby/object:Gem::Requirement
121
+ none: false
122
+ requirements:
123
+ - - ! '>='
124
+ - !ruby/object:Gem::Version
125
+ version: '0'
126
+ segments:
127
+ - 0
128
+ hash: -3134477564524655065
129
+ requirements: []
130
+ rubyforge_project:
131
+ rubygems_version: 1.8.23
132
+ signing_key:
133
+ specification_version: 3
134
+ summary: Remove gems installed by bundler
135
+ test_files:
136
+ - spec/cli_spec.rb
137
+ - spec/gem_list_spec.rb
138
+ - spec/keep_list_spec.rb
139
+ - spec/spec_helper.rb