gem_dating 0.1.1 → 0.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: ebf7931775d179eea359a6c01e14d3a194a4de2071d32bafbc9571a244459eb0
4
- data.tar.gz: 9b24ce47c704e0184cdb426828b8af87171fa7097f268a83ac02992c43131e26
3
+ metadata.gz: 50f8a606d682704f10a2ac5378c25a792d4c336ad08e05319e28333dc8ddfcb1
4
+ data.tar.gz: e8bc47b72796b1db95d67de3602d4bc6f27907807f80ad441b9f31faa7409596
5
5
  SHA512:
6
- metadata.gz: c4284c4873a6e5ec38181b7a09f0ac66830831b7cfe3513b3f30ab3aa8b477825608cb42d3c529f32fa47c3487c6e9bda7a57c303921d26a6f7deca53d8bfab6
7
- data.tar.gz: c975b8fb6164e3f99c9049bc59b92d5456b33c2370f91ac32b86539d3227b71646d6648975d6764bd0eb19a56e7575e22ad882c415ef8cf26b9bf47e4904a5fa
6
+ metadata.gz: abe1fdb44e970f1b0f0ae005104109da3f4cceb8124e081f81b4fc8a4727df70d0f51186879f96e7451c575aad4449fdeec2b9ef37790e695a1a0f5fe3f14839
7
+ data.tar.gz: f07e00ddc9906d3a5e378971bc09bbc709b2ba131b9740cbe0cb329c055a1283fb4536be6dbf110255d56860d72d0ac79f1768cab62763116472c511a806821b
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- gem_dating (0.1.1)
4
+ gem_dating (0.1.2)
5
5
  bundler
6
6
  table_print
7
7
 
@@ -56,8 +56,9 @@ GEM
56
56
  unicode-display_width (2.4.2)
57
57
 
58
58
  PLATFORMS
59
- arm64-darwin-21
60
59
  arm64-darwin-22
60
+ arm64-darwin-23
61
+ arm64-darwin-24
61
62
  x86_64-linux
62
63
 
63
64
  DEPENDENCIES
data/README.md CHANGED
@@ -4,11 +4,6 @@
4
4
 
5
5
  The primary use case is when evaluating a codebase for upgrades - a gem from 2017 may effectively be abandoned and could cause trouble if you're targeting an upgrade to Ruby 4.1
6
6
 
7
- `gem_dating` avoids utilizing Bundler, and intends to be useful where you want to evaluate a set of gems without
8
- the overhead of a full bundle install. If you've got a valid bundle you should consider the built in
9
- [bundle-outdated](https://bundler.io/v2.4/man/bundle-outdated.1.html), or other available tools for interacting
10
- with your Gemfile, like [libyear-bundler](https://github.com/jaredbeck/libyear-bundler).
11
-
12
7
  ## Usage
13
8
 
14
9
  If you have rubygems 3.4.8 or later installed, you can skip installation and just run via `gem exec gem_dating [[path/to/Gemfile]`
@@ -22,22 +17,42 @@ If you have rubygems 3.4.8 or later installed, you can skip installation and jus
22
17
  gem 'gem_dating', group: [:development], require: false
23
18
  ```
24
19
 
25
- ### Running GemDating
20
+ ### Command Line Options
26
21
 
27
- This gem provides a small command line interface. It may be invoked with:
22
+ GemDating supports several command line options to customize its behavior:
28
23
 
29
- ```bash
30
- $ gem_dating
24
+ ```
25
+ gem_dating [OPTIONS] [<GEMFILE_FILEPATH>]
31
26
  ```
32
27
 
33
- By default, GemDating will look for a Gemfile in the current directory.
34
- If it finds one, it will output a list of gems and their relative ages to the stdout stream.
28
+ #### Available Options:
35
29
 
36
- You may also pass a path to a Gemfile as an argument:
30
+ - `--help`, `-h`, `-?`: Show the help message
31
+ - `--older-than=<AGE>`, `--ot=<AGE>`: Filter gems updated within the last X time period
32
+ - Examples: `--older-than=2y` (2 years), `--ot=1m` (1 month), `--ot=4w` (4 weeks), `--ot=10d` (10 days)
33
+ - `--sort-by=<FIELD>`: Sort by field
34
+ - Available fields: `name` or `date`
35
+ - Default: `name`
36
+ - `--order=<DIRECTION>`: Sort direction
37
+ - Available directions: `asc` (ascending) or `desc` (descending)
38
+ - Default: `asc`
39
+ - `--json`: Output results as JSON instead of table format
40
+
41
+ #### Examples:
37
42
 
38
43
  ```bash
39
- $ gem_dating ~/code/my_app/Gemfile
40
- ```
44
+ # Show gems older than 1 year
45
+ $ gem_dating --older-than=1y
46
+
47
+ # Sort gems by date in descending order (newest first)
48
+ $ gem_dating --sort-by=date --order=desc
49
+
50
+ # Output results as JSON
51
+ $ gem_dating --json
52
+
53
+ # Combine multiple options
54
+ $ gem_dating ~/code/my_app/Gemfile --older-than=6m --sort-by=date --order=desc
55
+ ```
41
56
 
42
57
  GemDating leans on `$stdout`, so you can pipe the output to a file if you'd like:
43
58
  ```bash
@@ -86,6 +101,16 @@ more_dating.table_print
86
101
  # ...etc
87
102
  ```
88
103
 
104
+ ### Caveats
105
+
106
+ `gem_dating` avoids utilizing Bundler, and intends to be useful where you want to evaluate a set of gems without
107
+ the overhead of a full bundle install. If you've got a valid bundle you should consider the built in
108
+ [bundle-outdated](https://bundler.io/v2.4/man/bundle-outdated.1.html), or other available tools for interacting
109
+ with your Gemfile, like [libyear-bundler](https://github.com/jaredbeck/libyear-bundler).
110
+
111
+ Sometimes we [get incorrect dates](https://github.com/testdouble/gem_dating/issues/10).
112
+ TLDR; sometimes GemSpecs are built in an environment where the date gets overwritten. That'll be up to the gem
113
+ owner(s) to determine if they'd like to adjust it to provide accurate dates.
89
114
 
90
115
 
91
116
  ## Code of Conduct
data/Rakefile CHANGED
@@ -7,4 +7,4 @@ Rake::TestTask.new(:test) do |t|
7
7
  t.test_files = FileList["test/**/*_test.rb"]
8
8
  end
9
9
 
10
- task :default => :test
10
+ task default: :test
data/gem_dating.gemspec CHANGED
@@ -1,27 +1,26 @@
1
-
2
1
  lib = File.expand_path("../lib", __FILE__)
3
2
  $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
3
  require "gem_dating/version"
5
4
 
6
5
  Gem::Specification.new do |spec|
7
- spec.name = "gem_dating"
8
- spec.version = GemDating::VERSION
9
- spec.authors = ["Steve Jackson", "Daniel Huss"]
10
- spec.email = ["steve@testdouble.com"]
6
+ spec.name = "gem_dating"
7
+ spec.version = GemDating::VERSION
8
+ spec.authors = ["Steve Jackson", "Daniel Huss"]
9
+ spec.email = ["steve@testdouble.com"]
11
10
 
12
- spec.summary = "How old is that anyway?"
13
- spec.homepage = "https://github.com/testdouble/gem_dating"
14
- spec.license = "MIT"
11
+ spec.summary = "How old is that anyway?"
12
+ spec.homepage = "https://github.com/testdouble/gem_dating"
13
+ spec.license = "MIT"
15
14
 
16
15
  spec.metadata["homepage_uri"] = spec.homepage
17
16
  spec.metadata["source_code_uri"] = spec.homepage
18
17
  spec.metadata["changelog_uri"] = "#{spec.homepage}/blob/main/CHANGELOG.md"
19
18
 
20
- spec.files = Dir.chdir(File.expand_path('..', __FILE__)) do
19
+ spec.files = Dir.chdir(File.expand_path("..", __FILE__)) do
21
20
  `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
22
21
  end
23
- spec.bindir = "exe"
24
- spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
22
+ spec.bindir = "exe"
23
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
25
24
  spec.require_paths = ["lib"]
26
25
 
27
26
  spec.add_dependency "bundler"
@@ -10,7 +10,11 @@ module GemDating
10
10
  GEMFILE_FILEPATH defaults to ./Gemfile if not provided.
11
11
 
12
12
  Options:
13
- --help, -h Show this help message
13
+ --help, -h, -? Show this help message
14
+ --older-than=<AGE>, --ot=<AGE> Filter gems updated within the last X (e.g. 2y, 1m, 4w, 10d)
15
+ --sort-by=<FIELD> Sort by field (name or date), defaults to name
16
+ --order=<DIRECTION> Sort direction (asc or desc), defaults to asc
17
+ --json Output results as JSON
14
18
  HELP
15
19
 
16
20
  def initialize(argv = [])
@@ -18,10 +22,11 @@ module GemDating
18
22
 
19
23
  @args = args
20
24
  @file_path = file_path.first
25
+ @options = parse_args
21
26
  end
22
27
 
23
28
  def run
24
- if (@args & ['-h', '--help']).any?
29
+ if @options[:help]
25
30
  $stdout << HELP_TEXT
26
31
  return SUCCESS
27
32
  end
@@ -38,9 +43,33 @@ module GemDating
38
43
  end
39
44
  end
40
45
 
41
- $stdout << GemDating.from_file(@file_path).table_print << "\n"
46
+ result = GemDating.from_file(@file_path, @options)
47
+ output = @options[:json] ? result.to_json : result.table_print
48
+ $stdout << output << "\n"
42
49
 
43
50
  SUCCESS
44
51
  end
52
+
53
+ private
54
+
55
+ def parse_args(args = @args)
56
+ options = {}
57
+ options[:help] = true if (args & %w[-h --help -?]).any?
58
+ options[:json] = true if args.include?("--json")
59
+
60
+ if (older_than = args.find { |arg| arg.start_with?("--older-than=", "--ot=") })
61
+ options[:older_than] = older_than.split("=").last
62
+ end
63
+
64
+ if (sort_by = args.find { |arg| arg.start_with?("--sort-by=") })
65
+ options[:sort_by] = sort_by.split("=").last
66
+ end
67
+
68
+ if (order = args.find { |arg| arg.start_with?("--order=") })
69
+ options[:order] = order.split("=").last
70
+ end
71
+
72
+ options
73
+ end
45
74
  end
46
75
  end
@@ -23,7 +23,7 @@ module GemDating
23
23
  end
24
24
 
25
25
  def gem_line(line)
26
- single_word_ruby_statements = %w{end else # gemspec}
26
+ single_word_ruby_statements = %w[end else # gemspec]
27
27
  return if single_word_ruby_statements.include? line.strip
28
28
 
29
29
  if line.start_with? "gem("
@@ -1,4 +1,5 @@
1
1
  require "table_print"
2
+ require "json"
2
3
 
3
4
  module GemDating
4
5
  class Result
@@ -24,5 +25,57 @@ module GemDating
24
25
  def table_print
25
26
  TablePrint::Printer.table_print(specs, [:name, :version, {date: {time_format: "%Y-%m-%d", width: 10}}]).encode("utf-8")
26
27
  end
28
+
29
+ def to_json
30
+ JSON.generate(to_h)
31
+ end
32
+
33
+ def older_than(date)
34
+ specs.select! { |spec| spec.date.to_date < cut_off(date) }
35
+ self
36
+ end
37
+
38
+ def sort(options = {})
39
+ field = options[:sort_by] || "name"
40
+ direction = options[:order] || "asc"
41
+
42
+ @specs = @specs.sort_by do |spec|
43
+ case field
44
+ when "name"
45
+ spec.name.downcase
46
+ when "date"
47
+ spec.date
48
+ else
49
+ spec.name.downcase
50
+ end
51
+ end
52
+
53
+ @specs = @specs.reverse if direction.downcase == "desc"
54
+
55
+ self
56
+ end
57
+
58
+ private
59
+
60
+ def cut_off(date)
61
+ return unless date
62
+ curr_date = Date.today
63
+
64
+ number = date[0..-2].to_i
65
+ unit = date[-1]
66
+
67
+ case unit
68
+ when "y"
69
+ curr_date << (12 * number)
70
+ when "m"
71
+ curr_date << number
72
+ when "w"
73
+ curr_date - (number * 7)
74
+ when "d"
75
+ curr_date - number
76
+ else
77
+ raise ArgumentError, "Invalid date format: #{date}"
78
+ end
79
+ end
27
80
  end
28
81
  end
@@ -1,3 +1,3 @@
1
1
  module GemDating
2
- VERSION = "0.1.1"
2
+ VERSION = "0.1.2"
3
3
  end
data/lib/gem_dating.rb CHANGED
@@ -5,15 +5,23 @@ require_relative "gem_dating/result"
5
5
  require_relative "gem_dating/cli"
6
6
 
7
7
  module GemDating
8
- def self.from_string(s)
8
+ def self.from_string(s, options = {})
9
9
  gems = Input.string(s).gems
10
- specs = Rubygems.fetch(gems)
11
- Result.new(specs)
10
+ fetch_specs(gems, options)
12
11
  end
13
12
 
14
- def self.from_file(path)
13
+ def self.from_file(path, options = {})
15
14
  gems = Input.file(path).gems
15
+ fetch_specs(gems, options)
16
+ end
17
+
18
+ def self.fetch_specs(gems, options)
16
19
  specs = Rubygems.fetch(gems)
17
- Result.new(specs)
20
+ results = Result.new(specs)
21
+ results.older_than(options[:older_than]) if options[:older_than]
22
+ results.sort(options)
23
+ results
18
24
  end
25
+
26
+ private_class_method :fetch_specs
19
27
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: gem_dating
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.1
4
+ version: 0.1.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Steve Jackson
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: exe
11
11
  cert_chain: []
12
- date: 2023-11-27 00:00:00.000000000 Z
12
+ date: 2025-06-14 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: bundler
@@ -88,7 +88,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
88
88
  - !ruby/object:Gem::Version
89
89
  version: '0'
90
90
  requirements: []
91
- rubygems_version: 3.4.13
91
+ rubygems_version: 3.4.10
92
92
  signing_key:
93
93
  specification_version: 4
94
94
  summary: How old is that anyway?