bundler-stats 1.3.4 → 2.2.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: eee76f69e73d6036e090b2bee0eba231f835ebc2
4
- data.tar.gz: '09f8d3089540158fd2a06e8bd53ff0fbd2154bfd'
2
+ SHA256:
3
+ metadata.gz: fad76aec2c17866fce619ae8dbdaa4e580a58f1c0d89c53681a35dba5e266998
4
+ data.tar.gz: 27d5b7a9ac01d7f7c0856cd2422b127d18fcd4de1cda1b2bcb0bf5c596528ad6
5
5
  SHA512:
6
- metadata.gz: 83527495fddca9076679e2a409854e33c08654307aed35e0ca29daefef1f48726bfb8287430d5fab681f7401c0664ec6a86309560fee8442c0da805105fd132e
7
- data.tar.gz: 6710d3f9948e9c4721fc11767bd736184776db218db45895f019df84c66a8837ba75d6401d86f1bb79e8de523f8de5f167e758f57b5e4f688124cad688bda3aa
6
+ metadata.gz: 57c12161cd51c19804cfd15fb17903c1a1a9a82fe1347cd303230f5979539c7306165b926d5db4e65434d43c19c9a8649afbe0c30ee58a41cfebc2cdc653b250
7
+ data.tar.gz: ee3ffeaa9580d4866a8fb11a947274ecd70e926cfdd3db83147a04500ab2a76e15ce89384268911e7e45587d483501d81d44d13e5733fe4c79f5746820887563
@@ -0,0 +1,27 @@
1
+ name: CI
2
+
3
+ on:
4
+ push:
5
+ branches: [ master ]
6
+ pull_request:
7
+ branches: [ master ]
8
+
9
+ jobs:
10
+ test:
11
+ strategy:
12
+ matrix:
13
+ os: [ubuntu-latest, macos-latest]
14
+ ruby-version: [3.1, 3.0, 2.7, 2.6, 2.5, 2.4, 2.3]
15
+ runs-on: ${{ matrix.os }}
16
+
17
+ steps:
18
+ - uses: actions/checkout@v2
19
+ - name: Set up Ruby ${{ matrix.ruby-version }}
20
+ uses: ruby/setup-ruby@v1
21
+ with:
22
+ ruby-version: ${{ matrix.ruby-version }}
23
+ bundler-cache: true
24
+ - name: Install dependencies
25
+ run: bundle install
26
+ - name: Run tests
27
+ run: bundle exec rspec
data/.gitignore CHANGED
@@ -1 +1,2 @@
1
1
  Gemfile.lock
2
+ bundler-stats-*.gem
data/.rspec ADDED
@@ -0,0 +1 @@
1
+ --color
data/.ruby-version ADDED
@@ -0,0 +1 @@
1
+ 2.7.3
data/CHANGELOG.md CHANGED
@@ -1,19 +1,105 @@
1
1
  Changelog
2
2
  =============
3
3
 
4
- ## [1.1.0] - 2018-03-16
4
+ ## [2.2.0] - 2022-02-09
5
+
6
+ ### Added
7
+ - Support for gems.rb and gems.locked files.
8
+ - Proper exit codes from thor when errors occur
9
+ - Looser dependency on thor
10
+
11
+ ## [2.1.1] - 2021-11-30
12
+
13
+ ### Changed
14
+ - Symlink isn't the recommended way to alias a command. Patterned current
15
+ solution after bundle-audit. Boy that naming convention was unfortunate.
16
+ - Pin down dependencies a bit.
17
+
18
+ ### Added
19
+ - Moved to Github test workflow, by @etagwerker.
20
+ - New default ruby version to be most current non-3 ruby.
21
+ - Build artifacts now ignored.
22
+ - Moved to a real spec_helper so tests can be filtered during runs if desired.
23
+
5
24
  ### Fixed
25
+ - Failing test from previous version.
6
26
 
7
- - Remove unintentional inclusion of pry outside of dev environment
27
+ ## [2.1.0] - 2021-11-29
28
+
29
+ ### Changed
30
+ - Add Travis targets for more modern rubies, by @etagwerker.
31
+ - Make sorting predictable across platforms, by @etagwerker.
32
+
33
+ ### Fixed
34
+ - Fix error in CI when `tput` isn't available, by @etagwerker.
35
+
36
+ ## [2.0.1] - 2018-05-04
8
37
 
9
- ## [1.1.0] - 2018-03-15
10
38
  ### Added
39
+ - Complete custom table printer for some nicer output.
40
+
41
+ ## [2.0.0] - 2018-05-04
42
+ Broken as hell.
11
43
 
44
+ ## [1.3.4] - 2019-04-18
45
+
46
+ ### Changed
47
+ - Allow use of either `bundle-stats` or `bundler-stats` since the gem name was
48
+ a confusing choice. Live and learn.
49
+
50
+ ### Added
51
+ - Display resolved version of a gem when using `bundler-stats show`.
52
+
53
+ ## [1.3.3] - 2019-04-18
54
+
55
+ ### Changed
56
+ - Only print missing system dependency warning once per target gem, rather than
57
+ blowing up the console when a complicated gem is affected.
58
+
59
+ ## [1.3.2] - 2019-04-17
60
+
61
+ ### Fixed
62
+ - Fix issue when testing removability and a system gem from another platform
63
+ is "required", thx @rwojnarowski.
64
+
65
+ ## [1.3.1] - 2019-04-05
66
+
67
+ ### Changed
68
+ - Nicer table printing, still committed to not adding a table printing gem.
69
+
70
+ ## [1.3.0] - 2019-04-05
71
+
72
+ ### Changed
73
+ - Reversed the order in which gems are printed to worst-offenders-first.
74
+
75
+ ## [1.2.1] - 2019-04-05
76
+
77
+ ### Fixed
78
+ - When a system gem is missing from the lockfile (but is depended upon), warn
79
+ the user rather than exploding.
80
+
81
+ ## [1.2.0] - 2019-04-05
82
+
83
+ ### Fixed
84
+ - Loosen dependency on thor gem, by localhostdotdev.
85
+
86
+ ## [1.1.2] - 2018-03-16
87
+ Wonkiness w/ versioning. Apparently I was bad at this.
88
+
89
+ ## [1.1.0] - 2018-03-16
90
+ Eventually superseded by 1.1.2 for reasons.
91
+
92
+ ### Fixed
93
+ - Remove unintentional inclusion of pry outside of dev environment, per @Tuxified
94
+
95
+ ## [1.1.0] - 2018-03-15
96
+
97
+ ### Added
12
98
  - Adds a way to view dependency version restrictions for a given gem, by @olivierlacan
13
99
 
14
100
  ## [1.0.0] - 2016-04-13
15
- ### Added
16
101
 
102
+ ### Added
17
103
  - Base library, woo!
18
104
  - List all transitive dependencies and how many other deps rely on them
19
105
  - View list of Github-specified dependencies
data/Guardfile CHANGED
@@ -15,18 +15,6 @@
15
15
  #
16
16
  # and, you'll have to watch "config/Guardfile" instead of "Guardfile"
17
17
 
18
- guard :bundler do
19
- require 'guard/bundler'
20
- require 'guard/bundler/verify'
21
- helper = Guard::Bundler::Verify.new
22
-
23
- files = ['Gemfile']
24
- files += Dir['*.gemspec'] if files.any? { |f| helper.uses_gemspec?(f) }
25
-
26
- # Assume files are symlinked from somewhere
27
- files.each { |file| watch(helper.real_path(file)) }
28
- end
29
-
30
18
  guard :rspec, cmd: 'rspec' do
31
19
  watch(%r{^spec/.+_spec\.rb$})
32
20
  watch(%r{^lib/(.+)\.rb$}) { |m| "spec/lib/#{m[1]}_spec.rb" }
data/README.md CHANGED
@@ -1,15 +1,16 @@
1
1
  Bundler Stats
2
2
  =============
3
3
 
4
- You remember that time [someone yanked their library](http://blog.npmjs.org/post/141577284765/kik-left-pad-and-npm)
5
- and the entire Node universe fell apart? Yeah, me too. And all the
4
+ You remember that time [someone yanked their
5
+ library](http://blog.npmjs.org/post/141577284765/kik-left-pad-and-npm) and the
6
+ entire Node universe fell apart? Yeah, me too. And all the
6
7
  [thinkpieces](http://www.haneycodes.net/npm-left-pad-have-we-forgotten-how-to-program/)
7
- that came out just afterward were right: you should be careful about
8
- what dependencies you include in your project.
8
+ that came out just afterward were right: you should be careful about what
9
+ dependencies you include in your project.
9
10
 
10
11
  This project gives you some tools you can use with an existing Gemfile to
11
- determine which gems are including long trees of their own dependencies,
12
- and which you can potentially remove.
12
+ determine which gems are including long trees of their own dependencies, and
13
+ which you can potentially remove.
13
14
 
14
15
  This is an exploratory tool, and I'd be interested to hear what other criteria
15
16
  would be useful in determining what tools to remove.
@@ -33,75 +34,106 @@ Usage
33
34
  bundle-stats version # Prints the bundler-stats version
34
35
  bundle-stats versions TARGET # Shows versions requirements for target in other dependencies
35
36
 
36
- The most obvious thing to do is run the command by itself, which should help identify problem areas:
37
+ The most obvious thing to do is run the command by itself, which should help
38
+ identify problem areas:
37
39
 
38
40
  > bundle-stats
39
41
 
40
- +------------------------------|-----------------|-----------------+
41
- | Name | Total Deps | 1st Level Deps |
42
- +------------------------------|-----------------|-----------------+
43
- ... omitted stuff here ...
44
- | fog | 15 | 6 |
45
- | fancybox2-rails | 15 | 1 |
46
- | quiet_assets | 15 | 1 |
47
- | coffee-rails | 18 | 2 |
48
- | angular-rails-templates | 19 | 3 |
49
- | devise | 19 | 6 |
50
- | rspec-rails | 20 | 7 |
51
- | sass-rails | 21 | 4 |
52
- | foundation-icons-sass-rails | 22 | 2 |
53
- | rails | 29 | 9 |
54
- | angular_rails_csrf | 30 | 1 |
55
- | ngannotate-rails | 31 | 2 |
56
- | activeadmin | 48 | 12 |
57
- +------------------------------|-----------------|-----------------+
58
-
59
- Declared Gems: 35
60
- Total Gems: 113
61
-
62
- Unpinned Versions: 30
63
- Github Refs: 1
64
-
65
- It looks like activeadmin is a huge problem. Use `show` to investigate:
66
-
67
- > bundle-stats show activeadmin
68
- bundle-stats for activeadmin
69
-
70
- depended upon by (0) |
71
- depends on (48) | arbre, bourbon, coffee-rails, formtastic, formtastic_i18n, inherited_resources, jquery-rails, jquery-ui-rails, kaminari, rails, ransack, sass-rails, activesupport, i18n, json, minitest, thread_safe, tzinfo, sass, thor, coffee-script, railties, coffee-script-source, execjs, actionpack, rake, actionview, rack, rack-test, builder, erubis, has_scope, responders, actionmailer, activemodel, activerecord, bundler, sprockets-rails, mail, mime-types, treetop, polyglot, arel, sprockets, hike, multi_json, tilt, polyamorous
72
- unique to this (12) | arbre, bourbon, formtastic, formtastic_i18n, inherited_resources, jquery-rails, jquery-ui-rails, kaminari, ransack, has_scope, bundler, polyamorous
73
-
74
- Removing the dep will only actually remove 12 gems. The rest are shared dependencies with rails. We can also omit trees we aren't going to remove (hi rails) by not following them:
42
+ +----------------------------|------------|----------------+
43
+ | Name | Total Deps | 1st Level Deps |
44
+ +----------------------------|------------|----------------+
45
+ | rails_admin | 60 | 12 |
46
+ | rails | 40 | 12 |
47
+ | compass-rails | 35 | 3 |
48
+ | haml-rails | 29 | 5 |
49
+ | rspec-rails | 27 | 7 |
50
+ | sass-rails | 26 | 5 |
51
+ | devise | 26 | 5 |
52
+ | scenic | 25 | 2 |
53
+ | coffee-rails | 25 | 2 |
54
+ | guard-rubocop | 24 | 2 |
55
+ | versionist | 23 | 3 |
56
+ | factory_bot_rails | 23 | 2 |
57
+ | ... omitted stuff here ... |
58
+ +----------------------------|------------|----------------+
59
+
60
+ Declared Gems 56
61
+ Total Gems 170
62
+ Unpinned Versions 54
63
+ Github Refs 0
64
+
65
+ It looks like rails_admin is a huge problem. Use `show` to investigate:
66
+
67
+ > bundle-stats show rails_admin
68
+ bundle-stats for rails_admin
69
+
70
+ +--------------------------------|----------------------------------------+
71
+ | Depended Upon By (0) | |
72
+ | Depends On (60) | builder, coffee-rails |
73
+ | | font-awesome-rails, haml, jquery-rails |
74
+ | | jquery-ui-rails, kaminari, nested_form |
75
+ | | rack-pjax, rails, remotipart |
76
+ | | sass-rails, coffee-script, railties |
77
+ | | coffee-script-source, execjs |
78
+ | | actionpack, activesupport |
79
+ | | method_source, rake, thor, actionview |
80
+ | | rack, rack-test, rails-dom-testing |
81
+ | | rails-html-sanitizer, erubi |
82
+ | | concurrent-ruby, i18n, minitest |
83
+ | | tzinfo, thread_safe, nokogiri |
84
+ | | mini_portile2, loofah, crass, temple |
85
+ | | tilt, kaminari-actionview |
86
+ | | kaminari-activerecord, kaminari-core |
87
+ | | activerecord, activemodel, arel |
88
+ | | actioncable, actionmailer, activejob |
89
+ | | activestorage, bundler |
90
+ | | sprockets-rails, nio4r |
91
+ | | websocket-driver, websocket-extensions |
92
+ | | mail, globalid, mini_mime, marcel |
93
+ | | mimemagic, sprockets, sass |
94
+ | Unique to This (9) | font-awesome-rails, kaminari |
95
+ | | nested_form, rack-pjax, remotipart |
96
+ | | kaminari-actionview |
97
+ | | kaminari-activerecord, kaminari-core |
98
+ | | bundler |
99
+ +--------------------------------|----------------------------------------+
100
+
101
+ Removing the dep will only actually remove 9 gems. The rest are shared
102
+ dependencies with other gems like rails. We can also omit trees we aren't going
103
+ to remove (hi rails) by not following them:
75
104
 
76
105
  > bundle-stats show sass-rails --nofollow="railties,activesupport,actionpack"
77
106
  bundle-stats for sass-rails
78
107
 
79
- depended upon by (2) | activeadmin, foundation-icons-sass-rails
80
- depends on (10) | railties, sass, sprockets, sprockets-rails, hike, multi_json, rack, tilt, actionpack, activesupport
81
- unique to this (0) |
108
+ +--------------------------------|----------------------------------------+
109
+ | Depended Upon By (2) | compass-rails, rails_admin |
110
+ | Depends On (9) | railties, sass, sprockets |
111
+ | | sprockets-rails, tilt, concurrent-ruby |
112
+ | | rack, actionpack, activesupport |
113
+ | Unique to This (0) | |
114
+ +--------------------------------|----------------------------------------+
82
115
 
83
116
  To consume information with a build job or somesuch, all commands can emit JSON:
84
117
 
85
118
  > bundle-stats show sass-rails --nofollow="railties,activesupport,actionpack" -f json
86
119
  {
87
120
  "name": "sass-rails",
88
- "total_dependencies": 10,
89
- "first_level_dependencies": 4,
121
+ "total_dependencies": 9,
122
+ "first_level_dependencies": 5,
90
123
  "top_level_dependencies": {
91
- "activeadmin": "activeadmin (1.0.0.pre)",
92
- "foundation-icons-sass-rails": "foundation-icons-sass-rails (3.0.0)"
124
+ "compass-rails": "compass-rails (3.1.0)",
125
+ "rails_admin": "rails_admin (1.3.0)"
93
126
  },
94
127
  "transitive_dependencies": [
95
- "railties (< 5.0, >= 4.0.0)",
96
- "sass (~> 3.2.0)",
97
- "sprockets (<= 2.11.0, ~> 2.8)",
98
- "sprockets-rails (~> 2.0)",
99
- "hike (~> 1.2)",
100
- "multi_json (~> 1.0)",
101
- "rack (~> 1.0)",
102
- "tilt (!= 1.3.0, ~> 1.1)",
103
- "actionpack (>= 3.0)",
104
- "activesupport (>= 3.0)"
128
+ "railties (< 6, >= 4.0.0)",
129
+ "sass (~> 3.1)",
130
+ "sprockets (< 4.0, >= 2.8)",
131
+ "sprockets-rails (< 4.0, >= 2.0)",
132
+ "tilt (< 3, >= 1.1)",
133
+ "concurrent-ruby (~> 1.0)",
134
+ "rack (< 3, > 1)",
135
+ "actionpack (>= 4.0)",
136
+ "activesupport (>= 4.0)"
105
137
  ],
106
138
  "potential_removals": [
107
139
 
@@ -119,12 +151,13 @@ Contribution is expected to conform to the [Contributor Covenant](https://github
119
151
  Credits
120
152
  -------
121
153
 
122
- Thanks to the many kind people at [RailsCamp East 2016](http://east.railscamp.com)
123
- for the help, the ideas, and the support.
154
+ Thanks to the many kind people at [RailsCamp East
155
+ 2016](http://east.railscamp.com) for the help, the ideas, and the support.
124
156
 
125
- Thanks to Isaac Bowen for being pedantic about speeling.
157
+ Also, many other folks for their feature / fix contributions. ❤️
126
158
 
127
159
  License
128
160
  -------
129
161
 
130
- This software is released under the [MIT License](https://github.com/jmmastey/bundler-stats/blob/master/MIT-LICENSE).
162
+ This software is released under the [MIT
163
+ License](https://github.com/jmmastey/bundler-stats/blob/master/MIT-LICENSE).
data/bin/bundle-stats CHANGED
@@ -1,6 +1,5 @@
1
1
  #!/usr/bin/env ruby
2
2
 
3
-
4
3
  require 'rubygems'
5
4
 
6
5
  lib_dir = File.expand_path(File.join(File.dirname(__FILE__),'..','lib'))
data/bin/bundler-stats ADDED
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ load File.expand_path('../bundle-stats', __FILE__)
@@ -15,7 +15,7 @@ Gem::Specification.new do |gem|
15
15
  gem.licenses = "MIT"
16
16
  gem.authors = "Joseph Mastey"
17
17
  gem.email = "jmmastey@gmail.com"
18
- gem.homepage = ""
18
+ gem.homepage = "http://github.com/jmmastey/bundler-stats"
19
19
 
20
20
  gem.metadata = {
21
21
  "homepage_uri" => "http://github.com/jmmastey/bundler-stats",
@@ -35,10 +35,12 @@ Gem::Specification.new do |gem|
35
35
 
36
36
  gem.require_paths = %w[ext lib].select { |dir| File.directory?(dir) }
37
37
 
38
- gem.add_dependency "bundler", ">= 1.9"
39
- gem.add_dependency "thor", "~> 0.19"
38
+ gem.add_dependency "bundler", ">= 1.9", "< 3"
39
+ gem.add_dependency "thor", ">= 0.19.0", "< 2.0"
40
40
 
41
41
  gem.add_development_dependency "rspec", "~> 3.4"
42
42
  gem.add_development_dependency "guard", "~> 2.13"
43
+ gem.add_development_dependency "guard-rspec", "< 5"
43
44
  gem.add_development_dependency "pry", "~> 0.10"
45
+ gem.add_development_dependency "rb-readline", "< 1"
44
46
  end
@@ -64,7 +64,7 @@ module Bundler
64
64
  stats = @gemfile.map do |gem|
65
65
  @tree.summarize(gem.name)
66
66
  end
67
- stats.sort_by { |row| row[:total_dependencies] }.reverse
67
+ stats.sort_by { |row| [row[:total_dependencies] * -1, row[:name]] }
68
68
  end
69
69
  end
70
70
  end
@@ -59,56 +59,65 @@ module Bundler
59
59
 
60
60
  private
61
61
 
62
- # TODO: just install table_print, 'eh?
62
+ def self.exit_on_failure?
63
+ true
64
+ end
65
+
63
66
  def draw_stats(gem_stats, summary)
64
67
  max_name_length = gem_stats.map { |gem| gem[:name].length }.max
65
68
 
66
- say "+-#{"-" * max_name_length}-|-----------------|-----------------+"
67
- say "| %-#{max_name_length}s | Total Deps | 1st Level Deps |" % ["Name"]
68
- say "+-#{"-" * max_name_length}-|-----------------|-----------------+"
69
-
70
- gem_stats.each do |stat_line|
71
- say "| %-#{max_name_length}s | %-15s | %-15s |" % [stat_line[:name], stat_line[:total_dependencies], stat_line[:first_level_dependencies]]
72
- end
73
- say "+-#{"-" * max_name_length}-|-----------------|-----------------+"
69
+ say Printer.new(
70
+ headers: ["Name", "Total Deps", "1st Level Deps"],
71
+ data: gem_stats.map { |stat_line|
72
+ [stat_line[:name], stat_line[:total_dependencies], stat_line[:first_level_dependencies]]
73
+ }).to_s
74
+
75
+ say Printer.new(
76
+ headers: nil,
77
+ borders: false,
78
+ data: [
79
+ ["Declared Gems", summary[:declared]],
80
+ ["Total Gems", summary[:total]],
81
+ ["", ""],
82
+ ["Unpinned Versions", summary[:unpinned]],
83
+ ["Github Refs", summary[:github]],
84
+ ]).to_s
74
85
  say ""
75
- say "Declared Gems: #{summary[:declared]}"
76
- say "Total Gems: #{summary[:total]}"
77
- say ""
78
- say "Unpinned Versions: #{summary[:unpinned]}"
79
- say "Github Refs: #{summary[:github]}"
80
86
  end
81
87
 
82
88
  def draw_show(stats, target)
83
89
  say "bundle-stats for #{target}"
84
90
  say ""
85
- say "depended upon by (#{stats[:top_level_dependencies].count}) | #{stats[:top_level_dependencies].values.map(&:name).join(', ')}\n"
86
- say "depends on (#{stats[:transitive_dependencies].count}) | #{stats[:transitive_dependencies].map(&:name).join(', ')}\n"
87
- say "unique to this (#{stats[:potential_removals].count}) | #{stats[:potential_removals].map(&:name).join(', ')}\n"
88
- say ""
91
+
92
+ say Printer.new(
93
+ data: [
94
+ ["Depended Upon By (#{stats[:top_level_dependencies].count})", stats[:top_level_dependencies].values.map(&:name)],
95
+ ["Depends On (#{stats[:transitive_dependencies].count})", stats[:transitive_dependencies].map(&:name)],
96
+ ["Unique to This (#{stats[:potential_removals].count})", stats[:potential_removals].map(&:name)],
97
+ ]).to_s
89
98
  end
90
99
 
91
100
  def draw_versions(stats, target)
92
101
  dependers = stats[:top_level_dependencies] # they do the depending
93
102
  say "bundle-stats for #{target}"
94
- say ""
95
- say "Depended upon by #{stats[:top_level_dependencies].count}\n"
103
+ say Printer.new(
104
+ headers: nil,
105
+ borders: false,
106
+ data: [
107
+ ["Depended Upon By", stats[:top_level_dependencies].count],
108
+ ["Resolved Version", stats[:resolved_version]],
109
+ ]).to_s
96
110
 
97
- if stats[:resolved_version]
98
- say "Resolved version is #{stats[:resolved_version]}"
99
- end
100
111
  if dependers.count > 0
101
- max_name_length = dependers.map { |gem| gem[:name].length }.max
102
-
103
- say "+-#{"-" * max_name_length}-|-------------------+"
104
- say "| %-#{max_name_length}s | Required Version |" % ["Name"]
105
- say "+-#{"-" * max_name_length}-|-------------------+"
106
- dependers.each do |stat_line|
107
- say "| %-#{max_name_length}s | %-17s |" % [stat_line[:name], stat_line[:version]]
108
- end
109
- say "+-#{"-" * max_name_length}-|-------------------+"
110
112
  say ""
113
+ say Printer.new(
114
+ headers: ["Name", "Required Version"],
115
+ data: dependers.map { |stat_line|
116
+ [stat_line[:name], stat_line[:version]]
117
+ }).to_s
111
118
  end
119
+
120
+ say ""
112
121
  end
113
122
 
114
123
  def build_calculator(options)
@@ -124,19 +133,23 @@ module Bundler
124
133
  def gemfile_path
125
134
  cwd = Pathname.new("./")
126
135
  until cwd.realdirpath.root? do
127
- return (cwd + "Gemfile") if File.exist?(cwd + "Gemfile")
136
+ %w(gems.rb Gemfile).each do |gemfile|
137
+ return (cwd + gemfile) if File.exist?(cwd + gemfile)
138
+ end
128
139
  cwd = cwd.parent
129
140
  end
130
- raise ArgumentError, "Couldn't find Gemfile in this directory or parents"
141
+ raise ArgumentError, "Couldn't find gems.rb nor Gemfile in this directory or parents"
131
142
  end
132
143
 
133
144
  def lockfile_path
134
145
  cwd = Pathname.new(".")
135
146
  until cwd.realdirpath.root? do
136
- return (cwd + "Gemfile.lock") if File.exist?(cwd + "Gemfile.lock")
147
+ %w(gems.locked Gemfile.lock).each do |lockfile|
148
+ return (cwd + lockfile) if File.exist?(cwd + lockfile)
149
+ end
137
150
  cwd = cwd.parent
138
151
  end
139
- raise ArgumentError, "Couldn't find Gemfile in this directory or parents"
152
+ raise ArgumentError, "Couldn't find gems.locked nor Gemfile.lock in this directory or parents"
140
153
  end
141
154
  end
142
155
  end
@@ -0,0 +1,143 @@
1
+ # this is somewhat duplicative of the table_print gem, but tbh I like that we
2
+ # don't have many dependencies yet, so I'd rather keep it this way.
3
+ class Bundler::Stats::Printer
4
+ attr_accessor :headers, :data, :borders
5
+
6
+ MIN_COL_SIZE = 10
7
+
8
+ BORDERS = {
9
+ on: { corner: "+", horizontal: "-", vertical: "|" },
10
+ off: { corner: " ", horizontal: " ", vertical: " " },
11
+ }
12
+
13
+ def initialize(headers: nil, data: [], borders: true)
14
+ @headers = headers
15
+ @data = data
16
+ @borders = borders ? BORDERS[:on] : BORDERS[:off]
17
+ end
18
+
19
+ def to_s
20
+ table_data = ([headers] + data).compact
21
+ col_widths = column_widths(table_data)
22
+
23
+ lines = []
24
+ lines << separator_row(col_widths)
25
+
26
+ if headers
27
+ lines << aligned_row(headers, col_widths)
28
+ lines << separator_row(col_widths)
29
+ end
30
+
31
+ data.each do |row|
32
+ lines += split_rows(row, col_widths)
33
+ end
34
+ lines << separator_row(col_widths)
35
+
36
+ lines.join("\n")
37
+ end
38
+
39
+ def terminal_width
40
+ Integer(Kernel.send(:"`", "tput cols"))
41
+ rescue StandardError
42
+ 80
43
+ end
44
+
45
+ def column_widths(table_data)
46
+ num_cols = table_data.first.length
47
+ chrome = 2 + 2 + (num_cols - 1) * 3
48
+
49
+ # doesn't fit at all
50
+ if chrome + (num_cols * MIN_COL_SIZE) > terminal_width
51
+ raise ArgumentError, "Table smooshed. Refusing to print table."
52
+ end
53
+
54
+ data_widths = 0.upto(num_cols - 1).map do |idx|
55
+ max_width(table_data.map { |row| row[idx] })
56
+ end
57
+
58
+ # fits comfortably
59
+ if data_widths.inject(&:+) + chrome < terminal_width
60
+ return data_widths
61
+ end
62
+
63
+ free_space = terminal_width
64
+ free_space -= chrome
65
+ free_space -= MIN_COL_SIZE * num_cols
66
+
67
+ # fit uncomfortably
68
+ widths = [MIN_COL_SIZE] * num_cols
69
+ data_widths.each_with_index do |width, idx|
70
+ next unless width > widths[idx]
71
+
72
+ allocated = [width, free_space].min
73
+
74
+ if allocated > 0
75
+ widths[idx] += allocated
76
+ free_space -= allocated
77
+ end
78
+ end
79
+
80
+ widths
81
+ end
82
+
83
+ private
84
+
85
+ def max_width(data)
86
+ data.map do |value|
87
+ Array(value).join(", ").length
88
+ end.max
89
+ end
90
+
91
+ def separator_row(col_widths)
92
+ sep = "#{borders[:horizontal]}#{borders[:vertical]}#{borders[:horizontal]}"
93
+
94
+ "#{borders[:corner]}#{borders[:horizontal]}" +
95
+ col_widths.map { |width| borders[:horizontal] * width }.join(sep) +
96
+ "#{borders[:horizontal]}#{borders[:corner]}"
97
+ end
98
+
99
+ def split_rows(row, col_widths)
100
+ return [] unless row.find { |v| v && v.length > 0 }
101
+
102
+ rows_with_splits = [row]
103
+ next_row = []
104
+
105
+ joined_data = row.each_with_index.map do |val, idx|
106
+ words = Array(val).map(&:to_s)
107
+ target_width = col_widths[idx]
108
+
109
+ (cell, remainder) = row_and_remainder(words, target_width)
110
+
111
+ next_row[idx] = remainder
112
+ cell
113
+ end
114
+
115
+ ([aligned_row(joined_data, col_widths)] +
116
+ split_rows(next_row, col_widths)).compact
117
+ end
118
+
119
+ def row_and_remainder(words, target_width)
120
+ if(words.join(", ").length < target_width)
121
+ return [words.join(", "), nil]
122
+ end
123
+
124
+ this_row = []
125
+ while words.length > 0 && (this_row.join(", ").length + words[0].length) <= target_width
126
+ this_row << words.shift
127
+ end
128
+
129
+ [this_row.join(", "), words]
130
+ end
131
+
132
+ def aligned_row(row, col_widths)
133
+ aligned_values = row.each_with_index.map do |data, idx|
134
+ if idx == 0
135
+ data.rjust(col_widths[idx])
136
+ else
137
+ data.ljust(col_widths[idx])
138
+ end
139
+ end
140
+
141
+ "#{borders[:vertical]} " + aligned_values.join(" #{borders[:vertical]} ") + " #{borders[:vertical]}"
142
+ end
143
+ end
@@ -1,5 +1,5 @@
1
1
  module Bundler
2
2
  module Stats
3
- VERSION = '1.3.4'
3
+ VERSION = '2.2.0'
4
4
  end
5
5
  end
data/lib/bundler/stats.rb CHANGED
@@ -1,4 +1,5 @@
1
- require_relative 'stats/version'
2
- require_relative 'stats/tree'
3
- require_relative 'stats/remover'
4
1
  require_relative 'stats/calculator'
2
+ require_relative 'stats/printer'
3
+ require_relative 'stats/remover'
4
+ require_relative 'stats/tree'
5
+ require_relative 'stats/version'
@@ -1,5 +1,4 @@
1
- require 'bundler'
2
- require 'bundler/stats'
1
+ require 'spec_helper'
3
2
 
4
3
  describe Bundler::Stats::Calculator do
5
4
  subject { described_class }
@@ -77,6 +76,16 @@ describe Bundler::Stats::Calculator do
77
76
  end
78
77
 
79
78
  context "#gem_stats" do
79
+ let(:partial_sorted_result) do
80
+ [
81
+ ["rolify", 0],
82
+ ["rubocop-rspec", 0],
83
+ ["spring", 0],
84
+ ["state_machine", 0],
85
+ ["will_paginate", 0]
86
+ ]
87
+ end
88
+
80
89
  it "includes entries for each gem" do
81
90
  calculator = subject.new(gemfile_path, lockfile_path)
82
91
 
@@ -85,6 +94,14 @@ describe Bundler::Stats::Calculator do
85
94
  expect(target).to be_a(Array)
86
95
  expect(target.length).to eq(calculator.gemfile.length)
87
96
  end
97
+
98
+ it "sorts entries by total dependencies descending and name ascending" do
99
+ calculator = subject.new(gemfile_path, lockfile_path)
100
+
101
+ target = calculator.gem_stats
102
+ tuple = target.map {|x| [x[:name], x[:total_dependencies]] }
103
+ expect(tuple).to end_with(*partial_sorted_result)
104
+ end
88
105
  end
89
106
 
90
107
  context "#summary" do
@@ -0,0 +1,224 @@
1
+ require 'spec_helper'
2
+
3
+ describe Bundler::Stats::Printer do
4
+ subject { described_class }
5
+
6
+ def set_term_width(width)
7
+ allow(Kernel).to receive(:"`").and_return(width)
8
+ end
9
+
10
+ describe "#terminal_width" do
11
+ context "*nix systems" do
12
+ it "return the kernel width" do
13
+ set_term_width(180)
14
+
15
+ printer = subject.new
16
+ response = printer.terminal_width
17
+
18
+ expect(response).to eq(180)
19
+ end
20
+ end
21
+
22
+ context "non-*nix systems" do
23
+ it "always returns a small number" do
24
+ set_term_width(nil)
25
+
26
+ printer = subject.new
27
+ response = printer.terminal_width
28
+
29
+ expect(response).to eq(80)
30
+ end
31
+ end
32
+
33
+ context "tput returns an error" do
34
+ it "returns the default value" do
35
+ allow(Kernel).to receive(:send).and_return("tput: No value for $TERM and no -T specified")
36
+
37
+ printer = subject.new
38
+ response = printer.terminal_width
39
+
40
+ expect(response).to eq(80)
41
+ end
42
+ end
43
+ end
44
+
45
+ describe "#column_widths" do
46
+ it "comfortably prints tables of comfortable data" do
47
+ set_term_width(80)
48
+ printer = subject.new
49
+ table_data = [
50
+ [ "name", "data" ],
51
+ [ "*" * 10, "*" * 20 ],
52
+ ]
53
+
54
+ widths = printer.column_widths(table_data)
55
+
56
+ expect(widths).to eq([10, 20])
57
+ end
58
+
59
+ it "smooshes uncomfortably long data" do
60
+ set_term_width(60)
61
+ printer = subject.new
62
+ table_data = [
63
+ [ "name", "data" ],
64
+ [ "*" * 10, "*" * 60 ],
65
+ ]
66
+
67
+ widths = printer.column_widths(table_data)
68
+
69
+ target_widths = [10, 43] # 7 for gutters
70
+ expect(widths).to eq(target_widths)
71
+ end
72
+
73
+ it "always allows some amount of space for data" do
74
+ set_term_width(60)
75
+ printer = subject.new
76
+ table_data = [
77
+ [ "name", "data1", "data2", "data3" ],
78
+ [ "*" * 10, "*" * 60, "*" * 60, "*" * 60 ],
79
+ ]
80
+
81
+ widths = printer.column_widths(table_data)
82
+
83
+ target_widths = [10, 17, 10, 10] # 13 for gutters
84
+ expect(widths).to eq(target_widths)
85
+ end
86
+
87
+ it "bails if it can't handle that data" do
88
+ set_term_width(10)
89
+ printer = subject.new
90
+ table_data = [
91
+ [ "name", "data" ],
92
+ [ "*" * 10, "*" * 20 ],
93
+ ]
94
+
95
+ expect {
96
+ printer.column_widths(table_data)
97
+ }.to raise_error(ArgumentError)
98
+ end
99
+ end
100
+
101
+ describe "#to_s" do
102
+ it "prints a pretty table" do
103
+ set_term_width(80)
104
+ printer = subject.new(headers: ["stars", "stripes"],
105
+ data: [["*****", "*****"]]
106
+ )
107
+
108
+ output = printer.to_s
109
+ table = <<-TABLE
110
+ +-------|---------+
111
+ | stars | stripes |
112
+ +-------|---------+
113
+ | ***** | ***** |
114
+ +-------|---------+
115
+ TABLE
116
+
117
+ expect(output).to eq(table.chomp)
118
+ end
119
+
120
+ it "deals with data alignment" do
121
+ set_term_width(80)
122
+ printer = subject.new(headers: ["name", "value"],
123
+ data: [
124
+ ["one", "*****"],
125
+ ["seventeen", "///////////////"]
126
+ ])
127
+
128
+ output = printer.to_s
129
+ table = <<-TABLE
130
+ +-----------|-----------------+
131
+ | name | value |
132
+ +-----------|-----------------+
133
+ | one | ***** |
134
+ | seventeen | /////////////// |
135
+ +-----------|-----------------+
136
+ TABLE
137
+
138
+ expect(output).to eq(table.chomp)
139
+ end
140
+
141
+ it "wraps data as necessary" do
142
+ set_term_width(35)
143
+ printer = subject.new(headers: ["name", "value"],
144
+ data: [
145
+ ["words", ["one", "two", "three", "four", "five"]],
146
+ ])
147
+
148
+ output = printer.to_s
149
+ table = <<-TABLE
150
+ +------------|--------------------+
151
+ | name | value |
152
+ +------------|--------------------+
153
+ | words | one, two, three |
154
+ | | four, five |
155
+ +------------|--------------------+
156
+ TABLE
157
+
158
+ expect(output).to eq(table.chomp)
159
+ end
160
+
161
+ it "can wrap multiple columns" do
162
+ set_term_width(45)
163
+ printer = subject.new(headers: ["name", "value", "other value"],
164
+ data: [
165
+ [ "words",
166
+ ["one", "two", "three", "four", "five"],
167
+ ["six", "seven", "eight", "nine", "ten"],
168
+ ]
169
+ ])
170
+
171
+ output = printer.to_s
172
+ table = <<-TABLE
173
+ +------------|-----------------|------------+
174
+ | name | value | other value |
175
+ +------------|-----------------|------------+
176
+ | words | one, two, three | six, seven |
177
+ | | four, five | eight, nine |
178
+ | | | ten |
179
+ +------------|-----------------|------------+
180
+ TABLE
181
+
182
+ expect(output).to eq(table.chomp)
183
+ end
184
+
185
+ it "can print without a header" do
186
+ set_term_width(80)
187
+ printer = subject.new(headers: nil,
188
+ data: [
189
+ ["*****", "********"],
190
+ ["++++++++", "+++++"],
191
+ ])
192
+
193
+ output = printer.to_s
194
+ table = <<-TABLE
195
+ +----------|----------+
196
+ | ***** | ******** |
197
+ | ++++++++ | +++++ |
198
+ +----------|----------+
199
+ TABLE
200
+
201
+ expect(output).to eq(table.chomp)
202
+ end
203
+
204
+ it "can print without separators at all!" do
205
+ set_term_width(80)
206
+ printer = subject.new(headers: nil,
207
+ borders: false,
208
+ data: [
209
+ ["*****", "********"],
210
+ ["++++++++", "+++++"],
211
+ ])
212
+
213
+ output = printer.to_s
214
+ table = <<-TABLE
215
+
216
+ ***** ********
217
+ ++++++++ +++++
218
+
219
+ TABLE
220
+
221
+ expect(output).to eq(table.chomp)
222
+ end
223
+ end
224
+ end
@@ -1,5 +1,4 @@
1
- require 'bundler'
2
- require 'bundler/stats'
1
+ require 'spec_helper'
3
2
 
4
3
  LazyLazySpec = Struct.new(:name, :dependencies)
5
4
  FakeLockfileParser = Struct.new(:specs)
@@ -1,5 +1,4 @@
1
- require 'bundler'
2
- require 'bundler/stats'
1
+ require 'spec_helper'
3
2
 
4
3
  describe Bundler::Stats::Tree do
5
4
  subject { described_class }
@@ -0,0 +1,11 @@
1
+ require 'bundler'
2
+ require 'bundler/stats'
3
+
4
+ RSpec.configure do |config|
5
+ config.filter_run :focus
6
+ config.run_all_when_everything_filtered = true
7
+
8
+ config.expect_with :rspec do |expectations|
9
+ expectations.syntax = :expect
10
+ end
11
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: bundler-stats
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.3.4
4
+ version: 2.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Joseph Mastey
8
- autorequire:
8
+ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2019-04-18 00:00:00.000000000 Z
11
+ date: 2022-02-09 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -17,6 +17,9 @@ dependencies:
17
17
  - - ">="
18
18
  - !ruby/object:Gem::Version
19
19
  version: '1.9'
20
+ - - "<"
21
+ - !ruby/object:Gem::Version
22
+ version: '3'
20
23
  type: :runtime
21
24
  prerelease: false
22
25
  version_requirements: !ruby/object:Gem::Requirement
@@ -24,20 +27,29 @@ dependencies:
24
27
  - - ">="
25
28
  - !ruby/object:Gem::Version
26
29
  version: '1.9'
30
+ - - "<"
31
+ - !ruby/object:Gem::Version
32
+ version: '3'
27
33
  - !ruby/object:Gem::Dependency
28
34
  name: thor
29
35
  requirement: !ruby/object:Gem::Requirement
30
36
  requirements:
31
- - - "~>"
37
+ - - ">="
32
38
  - !ruby/object:Gem::Version
33
- version: '0.19'
39
+ version: 0.19.0
40
+ - - "<"
41
+ - !ruby/object:Gem::Version
42
+ version: '2.0'
34
43
  type: :runtime
35
44
  prerelease: false
36
45
  version_requirements: !ruby/object:Gem::Requirement
37
46
  requirements:
38
- - - "~>"
47
+ - - ">="
39
48
  - !ruby/object:Gem::Version
40
- version: '0.19'
49
+ version: 0.19.0
50
+ - - "<"
51
+ - !ruby/object:Gem::Version
52
+ version: '2.0'
41
53
  - !ruby/object:Gem::Dependency
42
54
  name: rspec
43
55
  requirement: !ruby/object:Gem::Requirement
@@ -66,6 +78,20 @@ dependencies:
66
78
  - - "~>"
67
79
  - !ruby/object:Gem::Version
68
80
  version: '2.13'
81
+ - !ruby/object:Gem::Dependency
82
+ name: guard-rspec
83
+ requirement: !ruby/object:Gem::Requirement
84
+ requirements:
85
+ - - "<"
86
+ - !ruby/object:Gem::Version
87
+ version: '5'
88
+ type: :development
89
+ prerelease: false
90
+ version_requirements: !ruby/object:Gem::Requirement
91
+ requirements:
92
+ - - "<"
93
+ - !ruby/object:Gem::Version
94
+ version: '5'
69
95
  - !ruby/object:Gem::Dependency
70
96
  name: pry
71
97
  requirement: !ruby/object:Gem::Requirement
@@ -80,6 +106,20 @@ dependencies:
80
106
  - - "~>"
81
107
  - !ruby/object:Gem::Version
82
108
  version: '0.10'
109
+ - !ruby/object:Gem::Dependency
110
+ name: rb-readline
111
+ requirement: !ruby/object:Gem::Requirement
112
+ requirements:
113
+ - - "<"
114
+ - !ruby/object:Gem::Version
115
+ version: '1'
116
+ type: :development
117
+ prerelease: false
118
+ version_requirements: !ruby/object:Gem::Requirement
119
+ requirements:
120
+ - - "<"
121
+ - !ruby/object:Gem::Version
122
+ version: '1'
83
123
  description: Looks through your lockfile and tries to identify problematic use of
84
124
  dependencies
85
125
  email: jmmastey@gmail.com
@@ -92,8 +132,10 @@ extra_rdoc_files:
92
132
  - CODE_OF_CONDUCT.md
93
133
  - README.md
94
134
  files:
135
+ - ".github/workflows/main.yml"
95
136
  - ".gitignore"
96
- - ".travis.yml"
137
+ - ".rspec"
138
+ - ".ruby-version"
97
139
  - CHANGELOG.md
98
140
  - CODE_OF_CONDUCT.md
99
141
  - Gemfile
@@ -106,22 +148,25 @@ files:
106
148
  - lib/bundler/stats.rb
107
149
  - lib/bundler/stats/calculator.rb
108
150
  - lib/bundler/stats/cli.rb
151
+ - lib/bundler/stats/printer.rb
109
152
  - lib/bundler/stats/remover.rb
110
153
  - lib/bundler/stats/tree.rb
111
154
  - lib/bundler/stats/version.rb
112
155
  - spec/lib/bundler/stats/calculator_spec.rb
156
+ - spec/lib/bundler/stats/printer_spec.rb
113
157
  - spec/lib/bundler/stats/remover_spec.rb
114
158
  - spec/lib/bundler/stats/tree_spec.rb
159
+ - spec/spec_helper.rb
115
160
  - spec/test_gemfile
116
161
  - spec/test_gemfile.lock
117
- homepage: ''
162
+ homepage: http://github.com/jmmastey/bundler-stats
118
163
  licenses:
119
164
  - MIT
120
165
  metadata:
121
166
  homepage_uri: http://github.com/jmmastey/bundler-stats
122
167
  changelog_uri: https://github.com/jmmastey/bundler-stats/blob/master/CHANGELOG.md
123
168
  source_code_uri: http://github.com/jmmastey/bundler-stats
124
- post_install_message:
169
+ post_install_message:
125
170
  rdoc_options: []
126
171
  require_paths:
127
172
  - lib
@@ -136,9 +181,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
136
181
  - !ruby/object:Gem::Version
137
182
  version: '0'
138
183
  requirements: []
139
- rubyforge_project:
140
- rubygems_version: 2.5.2.3
141
- signing_key:
184
+ rubygems_version: 3.1.6
185
+ signing_key:
142
186
  specification_version: 4
143
187
  summary: Dependency investigation for Bundler
144
188
  test_files: []
data/.travis.yml DELETED
@@ -1,6 +0,0 @@
1
- language: ruby
2
- script: bundle exec rspec
3
- rvm:
4
- - 2.3
5
- - 2.4
6
- - 2.5
data/bin/bundler-stats DELETED
@@ -1 +0,0 @@
1
- bundle-stats