Recently, for some work, I had a question about all the dependencies that a gem had. I went to the gem specification file and took a look – that obviously had a list of gems which had their own dependencies. I wanted to have a way to get all the dependencies so that I would know what I was dragging in by using a seemingly simple gem [like many people, I was wondering if using a Rails module by itself would drag too many things in].
One way to get an idea is to use Bundler and include the gem you want to check in a Gemfile and do a bundle install
– then, check the Gemfile.lock
but if you want to do a bit more, you might need to use a small script. As always, Google and StackOverflow are your friends. This led me to this page on StackOverflow that has a solution which is very close to it.
I used the script on that page as the starting point.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
class GemRequirements
def initialize(name, version = nil)
@gem = Gem::Dependency.new(name, version)
end
def dependency_tree
@dependency_tree ||= {}.merge(get_dependency(@gem))
end
private
def get_dependency(gem_dependency)
spec = gem_dependency.matching_specs.first
dep_key = "#{gem_dependency.name} #{spec.version}"
hash = { dep_key => {} }
spec.runtime_dependencies.each do |spec_dependency|
spec_dependency_spec = spec_dependency.matching_specs.first
spec_dep_key = "#{spec_dependency.name} #{spec_dependency_spec.version}"
hash[dep_key][spec_dep_key] = get_dependency(spec_dependency)
end
hash
end
end
This class is then run using this:
1
2
r = GemRequirements.new 'rails'
r.dependency_tree
This returns a hash that has the dependency tree. You can either just do a puts
to output the whole hash or use the built-in pp
to pretty print it:
1
2
3
4
require 'pp'
r = GemRequirements.new 'rails'
pp r.dependency_tree
The only problem that I had with this was that it does not output the unique list of gems and you still need to scan through the whole list. So, I added a small step to collect up the unique gems for outputting. I made some changes to calculate the list and the tree with some minor changes and this is as shown below.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
class GemRequirements
def initialize(name, version = nil)
@gem = Gem::Dependency.new(name, version)
@list = []
get_dependency(@gem)
end
def dependency_tree
@dependency_tree
end
def dependency_list
@dependency_list
end
private
def get_dependency(gem_dependency)
spec = gem_dependency.matching_specs.first
dep_key = "#{gem_dependency.name} #{spec.version}"
hash = { dep_key => {} }
spec.runtime_dependencies.each do |spec_dependency|
spec_dependency_spec = spec_dependency.matching_specs.first
spec_dep_key = "#{spec_dependency.name} #{spec_dependency_spec.version}"
@list << spec_dep_key
hash[dep_key][spec_dep_key] = get_dependency(spec_dependency)
end
@dependency_list = @list.uniq.sort
@dependency_tree = hash
end
end
Then, something like this will call the above class.
1
2
3
4
5
6
require 'pp'
r = GemRequirements.new 'rails'
pp r.dependency_tree
puts '--'
puts r.dependency_list
As always, this is for me to be able to remember how to do it but if it helps someone, that’s great! Also, if you have some comments, please add below so that I can reflect changes to the code.