bundler-stats 1.3.3 → 2.1.1

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
2
  SHA256:
3
- metadata.gz: 00521574e50038905fce9c0f58c700220922c38ff91ce987448e2372121333ff
4
- data.tar.gz: 76632e66f4e00c8cc0a00e4ae755fddbd29361526067140c3610b5023042008d
3
+ metadata.gz: 2c2cbaee0909835a5e655b3b148edd0448425beb1540f52f8b5e491440d66b7d
4
+ data.tar.gz: ca93d96c36ef79c6007ca752b2d8a747145dd5b075de83044d3080665dbbb19b
5
5
  SHA512:
6
- metadata.gz: 88b9b171219491c7590c41758137200a2c07e85456f4d21aaa00ea786b8c6574622ca872e133cf39bfc05603cb2372bd9a6dda67841b114f0c080abb4b471898
7
- data.tar.gz: 8fb71219134a7722f93811d61d29aef329a39cfd67a9d52a5a282de1dc708a3eada49321347e087fa8b4df73db16a2396cdf15acc9b34511ad69dde966a2b0f6
6
+ metadata.gz: 292b5afa7e530edc6a58fdb38a3f2c752f9e87c489c2e1c139562a80d9dcc177cf31473667a3a0329d99fb0b177bc3854e96a89fd1a4496ec7cab01e1564a30f
7
+ data.tar.gz: cf28a1e2379ebdaad08bdfe8e519b2faa924851964f60f006ac66a8175469680d0af16213faccf2199671e5238c275321fafb91084d790d8887bbc7162d71b6b
@@ -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.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,98 @@
1
1
  Changelog
2
2
  =============
3
3
 
4
- ## [1.1.0] - 2018-03-16
4
+ ## [2.1.1] - 2021-11-30
5
+
6
+ ### Changed
7
+ - Symlink isn't the recommended way to alias a command. Patterned current
8
+ solution after bundle-audit. Boy that naming convention was unfortunate.
9
+ - Pin down dependencies a bit.
10
+
11
+ ### Added
12
+ - Moved to Github test workflow, by @etagwerker.
13
+ - New default ruby version to be most current non-3 ruby.
14
+ - Build artifacts now ignored.
15
+ - Moved to a real spec_helper so tests can be filtered during runs if desired.
16
+
5
17
  ### Fixed
18
+ - Failing test from previous version.
6
19
 
7
- - Remove unintentional inclusion of pry outside of dev environment
20
+ ## [2.1.0] - 2021-11-29
21
+
22
+ ### Changed
23
+ - Add Travis targets for more modern rubies, by @etagwerker.
24
+ - Make sorting predictable across platforms, by @etagwerker.
25
+
26
+ ### Fixed
27
+ - Fix error in CI when `tput` isn't available, by @etagwerker.
28
+
29
+ ## [2.0.1] - 2018-05-04
8
30
 
9
- ## [1.1.0] - 2018-03-15
10
31
  ### Added
32
+ - Complete custom table printer for some nicer output.
33
+
34
+ ## [2.0.0] - 2018-05-04
35
+ Broken as hell.
36
+
37
+ ## [1.3.4] - 2019-04-18
38
+
39
+ ### Changed
40
+ - Allow use of either `bundle-stats` or `bundler-stats` since the gem name was
41
+ a confusing choice. Live and learn.
42
+
43
+ ### Added
44
+ - Display resolved version of a gem when using `bundler-stats show`.
45
+
46
+ ## [1.3.3] - 2019-04-18
47
+
48
+ ### Changed
49
+ - Only print missing system dependency warning once per target gem, rather than
50
+ blowing up the console when a complicated gem is affected.
51
+
52
+ ## [1.3.2] - 2019-04-17
53
+
54
+ ### Fixed
55
+ - Fix issue when testing removability and a system gem from another platform
56
+ is "required", thx @rwojnarowski.
11
57
 
58
+ ## [1.3.1] - 2019-04-05
59
+
60
+ ### Changed
61
+ - Nicer table printing, still committed to not adding a table printing gem.
62
+
63
+ ## [1.3.0] - 2019-04-05
64
+
65
+ ### Changed
66
+ - Reversed the order in which gems are printed to worst-offenders-first.
67
+
68
+ ## [1.2.1] - 2019-04-05
69
+
70
+ ### Fixed
71
+ - When a system gem is missing from the lockfile (but is depended upon), warn
72
+ the user rather than exploding.
73
+
74
+ ## [1.2.0] - 2019-04-05
75
+
76
+ ### Fixed
77
+ - Loosen dependency on thor gem, by localhostdotdev.
78
+
79
+ ## [1.1.2] - 2018-03-16
80
+ Wonkiness w/ versioning. Apparently I was bad at this.
81
+
82
+ ## [1.1.0] - 2018-03-16
83
+ Eventually superseded by 1.1.2 for reasons.
84
+
85
+ ### Fixed
86
+ - Remove unintentional inclusion of pry outside of dev environment, per @Tuxified
87
+
88
+ ## [1.1.0] - 2018-03-15
89
+
90
+ ### Added
12
91
  - Adds a way to view dependency version restrictions for a given gem, by @olivierlacan
13
92
 
14
93
  ## [1.0.0] - 2016-04-13
15
- ### Added
16
94
 
95
+ ### Added
17
96
  - Base library, woo!
18
97
  - List all transitive dependencies and how many other deps rely on them
19
98
  - 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"
38
+ gem.add_dependency "bundler", ">= 1.9", "< 3"
39
39
  gem.add_dependency "thor", "~> 0.19"
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,52 +59,61 @@ module Bundler
59
59
 
60
60
  private
61
61
 
62
- # TODO: just install table_print, 'eh?
63
62
  def draw_stats(gem_stats, summary)
64
63
  max_name_length = gem_stats.map { |gem| gem[:name].length }.max
65
64
 
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}-|-----------------|-----------------+"
74
- say ""
75
- say "Declared Gems: #{summary[:declared]}"
76
- say "Total Gems: #{summary[:total]}"
65
+ say Printer.new(
66
+ headers: ["Name", "Total Deps", "1st Level Deps"],
67
+ data: gem_stats.map { |stat_line|
68
+ [stat_line[:name], stat_line[:total_dependencies], stat_line[:first_level_dependencies]]
69
+ }).to_s
70
+
71
+ say Printer.new(
72
+ headers: nil,
73
+ borders: false,
74
+ data: [
75
+ ["Declared Gems", summary[:declared]],
76
+ ["Total Gems", summary[:total]],
77
+ ["", ""],
78
+ ["Unpinned Versions", summary[:unpinned]],
79
+ ["Github Refs", summary[:github]],
80
+ ]).to_s
77
81
  say ""
78
- say "Unpinned Versions: #{summary[:unpinned]}"
79
- say "Github Refs: #{summary[:github]}"
80
82
  end
81
83
 
82
84
  def draw_show(stats, target)
83
85
  say "bundle-stats for #{target}"
84
86
  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 ""
87
+
88
+ say Printer.new(
89
+ data: [
90
+ ["Depended Upon By (#{stats[:top_level_dependencies].count})", stats[:top_level_dependencies].values.map(&:name)],
91
+ ["Depends On (#{stats[:transitive_dependencies].count})", stats[:transitive_dependencies].map(&:name)],
92
+ ["Unique to This (#{stats[:potential_removals].count})", stats[:potential_removals].map(&:name)],
93
+ ]).to_s
89
94
  end
90
95
 
91
96
  def draw_versions(stats, target)
92
97
  dependers = stats[:top_level_dependencies] # they do the depending
93
98
  say "bundle-stats for #{target}"
94
- say ""
95
- say "depended upon by (#{stats[:top_level_dependencies].count})\n"
99
+ say Printer.new(
100
+ headers: nil,
101
+ borders: false,
102
+ data: [
103
+ ["Depended Upon By", stats[:top_level_dependencies].count],
104
+ ["Resolved Version", stats[:resolved_version]],
105
+ ]).to_s
106
+
96
107
  if dependers.count > 0
97
- max_name_length = dependers.map { |gem| gem[:name].length }.max
98
-
99
- say "+-#{"-" * max_name_length}-|-------------------+"
100
- say "| %-#{max_name_length}s | Required Version |" % ["Name"]
101
- say "+-#{"-" * max_name_length}-|-------------------+"
102
- dependers.each do |stat_line|
103
- say "| %-#{max_name_length}s | %-17s |" % [stat_line[:name], stat_line[:version]]
104
- end
105
- say "+-#{"-" * max_name_length}-|-------------------+"
106
108
  say ""
109
+ say Printer.new(
110
+ headers: ["Name", "Required Version"],
111
+ data: dependers.map { |stat_line|
112
+ [stat_line[:name], stat_line[:version]]
113
+ }).to_s
107
114
  end
115
+
116
+ say ""
108
117
  end
109
118
 
110
119
  def build_calculator(options)
@@ -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
@@ -25,7 +25,10 @@ class Bundler::Stats::Tree
25
25
 
26
26
  def version_requirements(target)
27
27
  transitive_dependencies = transitive_dependencies(target)
28
+ resolved_version = @tree[target].version if @tree.has_key?(target)
29
+
28
30
  { name: target,
31
+ resolved_version: resolved_version,
29
32
  total_dependencies: transitive_dependencies.count,
30
33
  first_level_dependencies: first_level_dependencies(target).count,
31
34
  top_level_dependencies: reverse_dependencies_with_versions(target),
@@ -1,5 +1,5 @@
1
1
  module Bundler
2
2
  module Stats
3
- VERSION = '1.3.3'
3
+ VERSION = '2.1.1'
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.3
4
+ version: 2.1.1
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: 2021-11-30 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,6 +27,9 @@ 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
@@ -66,6 +72,20 @@ dependencies:
66
72
  - - "~>"
67
73
  - !ruby/object:Gem::Version
68
74
  version: '2.13'
75
+ - !ruby/object:Gem::Dependency
76
+ name: guard-rspec
77
+ requirement: !ruby/object:Gem::Requirement
78
+ requirements:
79
+ - - "<"
80
+ - !ruby/object:Gem::Version
81
+ version: '5'
82
+ type: :development
83
+ prerelease: false
84
+ version_requirements: !ruby/object:Gem::Requirement
85
+ requirements:
86
+ - - "<"
87
+ - !ruby/object:Gem::Version
88
+ version: '5'
69
89
  - !ruby/object:Gem::Dependency
70
90
  name: pry
71
91
  requirement: !ruby/object:Gem::Requirement
@@ -80,19 +100,36 @@ dependencies:
80
100
  - - "~>"
81
101
  - !ruby/object:Gem::Version
82
102
  version: '0.10'
103
+ - !ruby/object:Gem::Dependency
104
+ name: rb-readline
105
+ requirement: !ruby/object:Gem::Requirement
106
+ requirements:
107
+ - - "<"
108
+ - !ruby/object:Gem::Version
109
+ version: '1'
110
+ type: :development
111
+ prerelease: false
112
+ version_requirements: !ruby/object:Gem::Requirement
113
+ requirements:
114
+ - - "<"
115
+ - !ruby/object:Gem::Version
116
+ version: '1'
83
117
  description: Looks through your lockfile and tries to identify problematic use of
84
118
  dependencies
85
119
  email: jmmastey@gmail.com
86
120
  executables:
87
121
  - bundle-stats
122
+ - bundler-stats
88
123
  extensions: []
89
124
  extra_rdoc_files:
90
125
  - CHANGELOG.md
91
126
  - CODE_OF_CONDUCT.md
92
127
  - README.md
93
128
  files:
129
+ - ".github/workflows/main.yml"
94
130
  - ".gitignore"
95
- - ".travis.yml"
131
+ - ".rspec"
132
+ - ".ruby-version"
96
133
  - CHANGELOG.md
97
134
  - CODE_OF_CONDUCT.md
98
135
  - Gemfile
@@ -100,26 +137,30 @@ files:
100
137
  - MIT-LICENSE
101
138
  - README.md
102
139
  - bin/bundle-stats
140
+ - bin/bundler-stats
103
141
  - bundler-stats.gemspec
104
142
  - lib/bundler/stats.rb
105
143
  - lib/bundler/stats/calculator.rb
106
144
  - lib/bundler/stats/cli.rb
145
+ - lib/bundler/stats/printer.rb
107
146
  - lib/bundler/stats/remover.rb
108
147
  - lib/bundler/stats/tree.rb
109
148
  - lib/bundler/stats/version.rb
110
149
  - spec/lib/bundler/stats/calculator_spec.rb
150
+ - spec/lib/bundler/stats/printer_spec.rb
111
151
  - spec/lib/bundler/stats/remover_spec.rb
112
152
  - spec/lib/bundler/stats/tree_spec.rb
153
+ - spec/spec_helper.rb
113
154
  - spec/test_gemfile
114
155
  - spec/test_gemfile.lock
115
- homepage: ''
156
+ homepage: http://github.com/jmmastey/bundler-stats
116
157
  licenses:
117
158
  - MIT
118
159
  metadata:
119
160
  homepage_uri: http://github.com/jmmastey/bundler-stats
120
161
  changelog_uri: https://github.com/jmmastey/bundler-stats/blob/master/CHANGELOG.md
121
162
  source_code_uri: http://github.com/jmmastey/bundler-stats
122
- post_install_message:
163
+ post_install_message:
123
164
  rdoc_options: []
124
165
  require_paths:
125
166
  - lib
@@ -134,9 +175,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
134
175
  - !ruby/object:Gem::Version
135
176
  version: '0'
136
177
  requirements: []
137
- rubyforge_project:
138
- rubygems_version: 2.7.3
139
- signing_key:
178
+ rubygems_version: 3.1.6
179
+ signing_key:
140
180
  specification_version: 4
141
181
  summary: Dependency investigation for Bundler
142
182
  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