Skip to content

Instantly share code, notes, and snippets.

@lucianghinda
Created December 1, 2023 04:40
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save lucianghinda/71ab2e5f54c566f9cd097e0a7ec57efa to your computer and use it in GitHub Desktop.
Save lucianghinda/71ab2e5f54c566f9cd097e0a7ec57efa to your computer and use it in GitHub Desktop.
Parse Ruby gems
require "prism"
class Parser
def initialize(list, rubygems_client: RubyGems::Client.new)
@list = list
@rubygems_client = rubygems_client
end
def parse
return parse_gemfile_format if gemfile_format?
parse_single_line_format
end
private
attr_reader :list, :rubygems_client
def gemfile_format? = lines.any? { gem_method_call?(_1) }
def parse_gemfile_format
ast = Prism.parse(list)
root_node = ast.value
parsed_gems = []
root_node.statements.body.each do |call_node|
case call_node.name
when :gem
name = gem_name_from_call_node(call_node)
parsed_gems << name
when :group
names = gem_names_from_group(call_node)
parsed_gems.concat(names) if names.present?
end
end
parsed_gems.compact_blank.map { rubygems_client.info(_1) }
end
def parse_single_line_format
lines.filter_map do |line|
gem_name = line.strip
gem_info = rubygems_client.info(gem_name) unless gem_name.empty?
gem_info
end.compact_blank
end
def gem_names_from_group(call_node)
statements_node = call_node&.block&.body
statements_node.body.map { gem_name_from_call_node(_1) }
end
def gem_name_from_call_node(call_node) = call_node&.arguments&.arguments&.first&.unescaped
def gem_method_call?(line) = line.strip.include?("gem ")
def lines = list.lines
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment