Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions Gemfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,8 @@ GEM

PLATFORMS
arm64-darwin-22
arm64-darwin-23
arm64-darwin-24
x86_64-linux

DEPENDENCIES
Expand Down
18 changes: 13 additions & 5 deletions lib/gem_dating.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,23 @@
require_relative "gem_dating/cli"

module GemDating
def self.from_string(s)
def self.from_string(s, options = {})
gems = Input.string(s).gems
specs = Rubygems.fetch(gems)
Result.new(specs)
fetch_specs(gems, options)
end

def self.from_file(path)
def self.from_file(path, options = {})
gems = Input.file(path).gems
fetch_specs(gems, options)
end


def self.fetch_specs(gems, options)
specs = Rubygems.fetch(gems)
Result.new(specs)
results = Result.new(specs)
results.older_than(options[:older_than]) if options[:older_than]
results
end

private_class_method :fetch_specs
end
19 changes: 16 additions & 3 deletions lib/gem_dating/cli.rb
Original file line number Diff line number Diff line change
Expand Up @@ -10,18 +10,20 @@ class Cli
GEMFILE_FILEPATH defaults to ./Gemfile if not provided.

Options:
--help, -h Show this help message
--help, -h, -? Show this help message
--older-than=<AGE>, --ot=<AGE> Filter gems updated within the last X (e.g. 2y, 1m, 4w, 10d)
HELP

def initialize(argv = [])
args, file_path = argv.partition { |arg| (arg =~ /--\w+/) || (arg =~ /(-[a-z])/) }

@args = args
@file_path = file_path.first
@options = parse_args
end

def run
if (@args & ['-h', '--help']).any?
if @options[:help]
$stdout << HELP_TEXT
return SUCCESS
end
Expand All @@ -38,9 +40,20 @@ def run
end
end

$stdout << GemDating.from_file(@file_path).table_print << "\n"
$stdout << GemDating.from_file(@file_path, @options).table_print << "\n"

SUCCESS
end

private

def parse_args(args = @args)
options = {}
options[:help] = true if (args & %w[-h --help -?]).any?
if (older_than = args.find { |arg| arg.start_with?("--older-than=", "--ot=") })
options[:older_than] = older_than.split("=").last
end
options
end
end
end
27 changes: 27 additions & 0 deletions lib/gem_dating/result.rb
Original file line number Diff line number Diff line change
Expand Up @@ -24,5 +24,32 @@ def to_h
def table_print
TablePrint::Printer.table_print(specs, [:name, :version, {date: {time_format: "%Y-%m-%d", width: 10}}]).encode("utf-8")
end

def older_than(date)
specs.select! { |spec| spec.date.to_date < self.cut_off(date) }
end

private

def cut_off(date)
return unless date
curr_date = Date.today

number = date[0..-2].to_i
unit = date[-1]

case unit
when "y"
curr_date << (12 * number)
when "m"
curr_date << number
when "w"
curr_date - (number * 7)
when "d"
curr_date - number
else
raise ArgumentError, "Invalid date format: #{date}"
end
end
end
end
20 changes: 14 additions & 6 deletions test/cli_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -61,12 +61,12 @@ def test_default_to_existing_relative_gemfile
end

expected_out = <<~EXPECTED
NAME | VERSION | DATE
----------------|----------|-----------
banana-client | 21.1.0 | 1990-08-21
rails-on-rubies | 70.0.5 | 2123-05-24
giraffeql | 0.0.2227 | 2023-05-17
EXPECTED
NAME | VERSION | DATE
----------------|----------|-----------
banana-client | 21.1.0 | 1990-08-21
rails-on-rubies | 70.0.5 | 2123-05-24
giraffeql | 0.0.2227 | 2023-05-17
EXPECTED

assert_equal 0, exit_code
assert_equal expected_out, stdout
Expand Down Expand Up @@ -109,4 +109,12 @@ def test_help_option
assert_includes expected_out, stdout.split("\n").first
assert_includes expected_out, stdout.split("\n").last
end

def test_parse_args
cli = GemDating::Cli.new(["--help", "--older-than=2y"])
assert_equal({ help: true, older_than: "2y" }, cli.send(:parse_args))

cli = GemDating::Cli.new([])
assert_equal({}, cli.send(:parse_args))
end
end
59 changes: 59 additions & 0 deletions test/result_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,15 @@
require "date"

class TestResult < Minitest::Test

def build_mock_spec(name:, version:, date:)
spec = Gem::Specification.new
spec.name = name
spec.version = Gem::Version.new(version)
spec.date = date
spec
end

def setup
@spec1 = Gem::Specification.new do |s|
s.name = "hi"
Expand All @@ -14,6 +23,18 @@ def setup
s.date = DateTime.parse("2009-09-02")
end
@result = GemDating::Result.new([@spec1, @spec2])

today = Date.today

@recent_gem = build_mock_spec(name: "recent", version: "1.0", date: today - 10)
@months_old_gem = build_mock_spec(name: "months_old", version: "1.0", date: today << 2)
@year_old_gem = build_mock_spec(name: "year_old", version: "1.0", date: today - 400)

@date_result = GemDating::Result.new([
@recent_gem,
@months_old_gem,
@year_old_gem
])
end

def test_specs
Expand Down Expand Up @@ -51,4 +72,42 @@ def test_table
assert_equal line.strip, table.split[index].strip
end
end

def test_cut_off_parsing_years
@date_result.older_than("1y")

assert_equal @date_result.specs.include?(@year_old_gem), true
assert_equal @date_result.specs.include?(@months_old_gem), false
assert_equal @date_result.specs.include?(@recent_gem), false
end

def test_cut_off_parsing_months
@date_result.older_than("1m")

assert_equal @date_result.specs.include?(@year_old_gem), true
assert_equal @date_result.specs.include?(@months_old_gem), true
assert_equal @date_result.specs.include?(@recent_gem), false
end

def test_cut_off_parsing_weeks
@date_result.older_than("3w")

assert_equal @date_result.specs.include?(@year_old_gem), true
assert_equal @date_result.specs.include?(@months_old_gem), true
assert_equal @date_result.specs.include?(@recent_gem), false
end

def test_cut_off_parsing_days
@date_result.older_than("7d")

assert_equal @date_result.specs.include?(@year_old_gem), true
assert_equal @date_result.specs.include?(@months_old_gem), true
assert_equal @date_result.specs.include?(@recent_gem), true
end

def test_cut_off_invalid_format_raises
assert_raises(ArgumentError) { @date_result.older_than("5x") }
assert_raises(ArgumentError) { @date_result.older_than("abc") }
assert_raises(ArgumentError) { @date_result.older_than("") }
end
end
12 changes: 12 additions & 0 deletions test/rubygems_test.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
require "test_helper"
require "date"

class GemDating::RubygemsTest < Minitest::Test
def test_unknown_version_returns_spec_with_defaults
rubygems = GemDating::Rubygems.new
spec = rubygems.unknown_version("foobar")
assert_equal "foobar", spec.name
assert_equal Gem::Version.new("0.0.0.UNKNOWN"), spec.version
assert_equal Date.parse("1970-01-01"), spec.date.to_date
end
end