strong_versions 0.4.0 → 0.4.5

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: f73f7623edb5e3a662b18ea78cd67822dfdbcc81bd6eb0e9332e80bd1eda57c6
4
- data.tar.gz: 9ed40edc5e76826e6458848fadd2b92a5b9f0985cefa0a3e56943c176e32edbb
3
+ metadata.gz: 4e3d02b2717fbfdc7da2e7cc0d83b495e01bc6b31efae98f635abae1cf8bf837
4
+ data.tar.gz: fb28b5ddd0a45c7ca56306bcfd58013824c9949bcd723a324dde98431f0b197c
5
5
  SHA512:
6
- metadata.gz: 17fc0b16150395edf3d57daed7893803fd012311620285ad3a57df5330cfb28b1c1eebde904ece4484c5651c203dc27eeeb34f4699d79e6d443954020da23f81
7
- data.tar.gz: 67d7d4dd885f70cf4877e72180311545606abc33d8191039c95c9afdcc2d2ef8a081222ab4fa56207e23e7830fa9adda0269444c093d8983e4c227119f9fe82a
6
+ metadata.gz: c4482cf23782277e84fdbf1a3a3e9d998c5cac84202d3c21be563dc4eeb21cdd5c6ba54490ff4f2e81d85899cde8eed32e28879e3a0f861871a1cd5a45b51491
7
+ data.tar.gz: fccdb21e6f7b58966a4f6dcee95ae6c176ae7be7b5380f820b660235f7a56f80163414475e9a4799d50d369f1ab73ddd354da98ba9aba83db03eb74c82f1cce3
@@ -11,4 +11,52 @@ Style/FormatStringToken:
11
11
  - 'lib/strong_versions/terminal.rb'
12
12
  AllCops:
13
13
  Exclude:
14
- - 'bin/**/*'
14
+ - 'bin/rake'
15
+ - 'bin/console'
16
+ - 'bin/rspec'
17
+ - 'bin/rubocop'
18
+ - 'bin/setup'
19
+
20
+ Layout/SpaceAroundMethodCallOperator:
21
+ Enabled: true
22
+
23
+ Lint/RaiseException:
24
+ Enabled: true
25
+
26
+ Lint/StructNewOverride:
27
+ Enabled: true
28
+
29
+ Style/ExponentialNotation:
30
+ Enabled: true
31
+
32
+ Style/HashEachMethods:
33
+ Enabled: true
34
+
35
+ Style/HashTransformKeys:
36
+ Enabled: true
37
+
38
+ Style/HashTransformValues:
39
+ Enabled: true
40
+
41
+ Layout/EmptyLinesAroundAttributeAccessor:
42
+ Enabled: true
43
+
44
+ Style/SlicingWithRange:
45
+ Enabled: true
46
+
47
+ Lint/DeprecatedOpenSSLConstant:
48
+ Enabled: true
49
+ Lint/MixedRegexpCaptureTypes:
50
+ Enabled: true
51
+ Style/AccessorGrouping:
52
+ Enabled: true
53
+ Style/BisectedAttrAccessor:
54
+ Enabled: true
55
+ Style/RedundantAssignment:
56
+ Enabled: true
57
+ Style/RedundantFetchBlock:
58
+ Enabled: true
59
+ Style/RedundantRegexpCharacterClass:
60
+ Enabled: true
61
+ Style/RedundantRegexpEscape:
62
+ Enabled: true
data/Makefile CHANGED
@@ -1,6 +1,5 @@
1
1
  .PHONY: test
2
2
  test:
3
- @bin/rspec
4
- @bundle exec bin/strong_versions
5
- @bin/rubocop
6
- @bin/rubocop bin/strong_versions
3
+ @bundle exec rspec
4
+ @bundle exec strong_versions
5
+ @bundle exec rubocop
data/README.md CHANGED
@@ -1,11 +1,5 @@
1
1
  # StrongVersions
2
2
 
3
- ```
4
- The right thing to guide us
5
- Is right here inside us
6
- --Nickelback
7
- ```
8
-
9
3
  # Overview
10
4
 
11
5
  _StrongVersions_ enforces a strict policy on your `Gemfile` requirements:
@@ -13,13 +7,13 @@ _StrongVersions_ enforces a strict policy on your `Gemfile` requirements:
13
7
  * The pessimistic `~>` operator must be used for all gem requirement definitions.
14
8
  * If the gem version is greater than 1, the requirement format must be `major.minor`, e.g. `'~> 2.5`'
15
9
  * If the gem version is less than 1, the requirement format must be `major.minor.patch`, e.g. `'~> 0.8.9'`
16
- * An upper bound can be specified as long as a valid pessimistic version is also specified, e.g. `'~> 8.4', '< 8.6.7' # Bug introduced in 8.6.7`
10
+ * A lower/upper bound can be specified as long as a valid pessimistic version is also specified, e.g. `'~> 8.4', '< 8.6.7'`
17
11
  * All gems with a `path` or `git` source are ignored, e.g. `path: '/path/to/gem'`, `git: 'https://github.com/bobf/strong_versions'`
18
12
  * All gems specified in the [ignore list](#ignore) are ignored.
19
13
 
20
- Any gems that do not satisfy these rules will be included in included in the _StrongVersions_ output with details on why they did not meet the standard.
14
+ Any gems that do not satisfy these rules will be included in the _StrongVersions_ output with details on why they did not meet the standard.
21
15
 
22
- The benefit of applying this standard is that, if all gems follow [Semantic Versioning](https://semver.org/) always be relatively safe to run `bundle update` to upgrade to the latest compatible versions of all dependencies. Running `bundle update` often brings advantages both in terms of bug fixes and security updates.
16
+ When all gems in a `Gemfile` follow this convention it SHOULD always be safe to run `bundle update` (assuming all gems adhere to [Semantic Versioning](https://semver.org/)).
23
17
 
24
18
  ![StrongVersions](doc/images/strong-versions-example.png)
25
19
 
@@ -28,7 +22,7 @@ The benefit of applying this standard is that, if all gems follow [Semantic Vers
28
22
  Add the gem to your `Gemfile`
29
23
 
30
24
  ```ruby
31
- gem 'strong_versions', '~> 0.4.0'
25
+ gem 'strong_versions', '~> 0.4.5'
32
26
  ```
33
27
 
34
28
  And rebuild your bundle:
@@ -37,11 +31,6 @@ And rebuild your bundle:
37
31
  $ bundle install
38
32
  ```
39
33
 
40
- Or install yourself:
41
- ```bash
42
- $ gem install strong_versions -v '0.4.0'
43
- ```
44
-
45
34
  ## Usage
46
35
 
47
36
  _StrongVersions_ is invoked with a provided executable:
@@ -54,7 +43,7 @@ The executable will output all non-passing gems and will return an exit code of
54
43
 
55
44
  ![StrongVersions](doc/images/ci-pipeline.png)
56
45
 
57
- If you are feeling brave, auto-correct is available:
46
+ Auto-correct is available with the `-a/--auto-correct` option:
58
47
  ```bash
59
48
  $ bundle exec strong_versions -a
60
49
  ```
@@ -69,6 +58,7 @@ ignore:
69
58
  - rails
70
59
  ```
71
60
 
61
+ Gems in the ignore list will not be updated when using the `-a/--auto-correct` option.
72
62
  ## Contributing
73
63
 
74
64
  Fork and create a pull request.
@@ -1,6 +1,7 @@
1
1
  #!/usr/bin/env ruby
2
2
  # frozen_string_literal: true
3
3
 
4
+ require 'bundler/setup'
4
5
  require 'optparse'
5
6
  require 'shellwords'
6
7
 
@@ -12,11 +13,11 @@ options = {}
12
13
  OptionParser.new do |opts|
13
14
  opts.banner = 'Usage: strong_versions [options]'
14
15
 
15
- opts.on('-a', '--auto-correct', 'Auto-correct (use with caution)') do |_v|
16
+ opts.on('-a', '--auto-correct', 'Auto-correct (use with caution)') do
16
17
  options[:auto_correct] = true
17
18
  end
18
19
 
19
- opts.on('--no-auto-correct', 'Disable auto-correct') do |_v|
20
+ opts.on('--no-auto-correct', 'Disable auto-correct') do
20
21
  options[:auto_correct] = false
21
22
  end
22
23
  end.parse!
@@ -33,11 +34,12 @@ validated = StrongVersions::Dependencies.new(dependencies).validate!(
33
34
  auto_correct: options[:auto_correct]
34
35
  )
35
36
 
37
+ exit 0 if validated
38
+
36
39
  if options[:auto_correct]
37
40
  # Re-evaluate
38
41
  args = original_args.map { |arg| Shellwords.escape(arg) }.join(' ')
39
42
  exec "#{$PROGRAM_NAME} #{args} --no-auto-correct"
40
43
  end
41
44
 
42
- exit 0 if validated
43
45
  exit 1
@@ -1,12 +1,14 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'optparse'
2
4
 
3
5
  require 'strong_versions'
4
6
 
5
7
  options = {}
6
8
  OptionParser.new do |opts|
7
- opts.banner = "Usage: strong_versions [options]"
9
+ opts.banner = 'Usage: strong_versions [options]'
8
10
 
9
- opts.on("-a", "--auto-correct", "Auto-correct (use with caution)") do |v|
11
+ opts.on('-a', '--auto-correct', 'Auto-correct (use with caution)') do |_v|
10
12
  options[:auto_correct] = true
11
13
  end
12
14
  end.parse!
@@ -24,12 +26,13 @@ validated = StrongVersions::Dependencies.new(dependencies).validate!(
24
26
  )
25
27
 
26
28
  revalidated = false
27
- revalidated = StrongVersions::Dependencies.new(dependencies).validate!(
28
- except: config.exceptions,
29
- on_failure: 'warn',
30
- auto_correct: false
31
- ) if options[:auto_correct]
29
+ if options[:auto_correct]
30
+ revalidated = StrongVersions::Dependencies.new(dependencies).validate!(
31
+ except: config.exceptions,
32
+ on_failure: 'warn',
33
+ auto_correct: false
34
+ )
35
+ end
32
36
 
33
- exit 0 if validated or revalidated
37
+ exit 0 if validated || revalidated
34
38
  exit 1
35
-
@@ -1,5 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require 'pathname'
3
4
  require 'yaml'
4
5
 
5
6
  require 'i18n'
@@ -10,8 +11,9 @@ require 'strong_versions/dependency'
10
11
  require 'strong_versions/dependency_finder'
11
12
  require 'strong_versions/dependencies'
12
13
  require 'strong_versions/errors'
13
- require 'strong_versions/suggestion'
14
14
  require 'strong_versions/terminal'
15
+ require 'strong_versions/gem_version'
16
+ require 'strong_versions/regexes'
15
17
  require 'strong_versions/version'
16
18
 
17
19
  module StrongVersions
@@ -17,7 +17,7 @@ module StrongVersions
17
17
  return true
18
18
  end
19
19
 
20
- return update_gemfile if auto_correct
20
+ return update_definitions(options.fetch(:except, [])) if auto_correct
21
21
 
22
22
  raise_or_warn(options.fetch(:on_failure, 'raise'))
23
23
  summary
@@ -45,38 +45,47 @@ module StrongVersions
45
45
  @terminal.summary(@dependencies.size, @invalid_gems.size)
46
46
  end
47
47
 
48
- def update_gemfile
49
- updated = 0
50
- @dependencies.each do |dependency|
51
- next unless dependency.updatable?
48
+ def updatable_dependencies(except)
49
+ @dependencies.reject { |dependency| except.include?(dependency.name) }
50
+ .select(&:updatable?)
51
+ end
52
52
 
53
- updated += 1 if update_dependency(dependency)
53
+ def update_definitions(except)
54
+ @terminal.update_summary(update(:gemfile, except) + update(:gemspec, except))
55
+ end
56
+
57
+ def update(subject, except)
58
+ updatable_dependencies(except).reduce(0) do |count, dependency|
59
+ update_dependency(subject, dependency) ? count : count + 1
54
60
  end
55
- @terminal.update_summary(updated)
56
61
  end
57
62
 
58
- def update_dependency(dependency)
59
- path = dependency.gemfile
63
+ def update_dependency(subject, dependency)
64
+ path = dependency.public_send(subject)
65
+ return if path.nil?
66
+
60
67
  content = File.read(path)
61
- update = replace_gem_definition(dependency, content)
68
+ update = replace_gem_definition(subject, dependency, content)
62
69
  return false if content == update
63
70
 
64
71
  File.write(path, update)
65
- @terminal.gem_update(path, dependency)
72
+ @terminal.gem_update(path, dependency, subject)
66
73
  true
67
74
  end
68
75
 
69
- def replace_gem_definition(dependency, content)
70
- regex = gem_regex(dependency.name)
76
+ def replace_gem_definition(subject, dependency, content)
77
+ regex = gem_regex(subject, dependency.name)
71
78
  match = content.match(regex)
72
79
  return content unless match
73
80
 
81
+ # For gemspec, indent includes the `spec.` or `s.` prefix.
74
82
  indent = match.captures.first
75
- content.gsub(regex, "#{indent}#{dependency.suggested_definition}")
83
+ definition = dependency.suggested_definition(subject)
84
+ content.gsub(regex, "#{indent}#{definition}")
76
85
  end
77
86
 
78
- def gem_regex(name)
79
- /^(\s*)gem\s+['"]#{name}['"].*$/
87
+ def gem_regex(subject, name)
88
+ Regexes.public_send(subject, name)
80
89
  end
81
90
 
82
91
  def raise_or_warn(on_failure)
@@ -1,6 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module StrongVersions
4
+ # rubocop:disable Metrics/ClassLength
4
5
  class Dependency
5
6
  attr_reader :name, :errors
6
7
 
@@ -13,37 +14,73 @@ module StrongVersions
13
14
  versions.each { |operator, version| validate_version(operator, version) }
14
15
  end
15
16
 
17
+ def to_s
18
+ "#<StrongVersions::Dependency name=#{@dependency.name}>"
19
+ end
20
+
16
21
  def gemfile
17
22
  Pathname.new(@dependency.gemfile) if @dependency.respond_to?(:gemfile)
18
23
  end
19
24
 
25
+ def gemspec
26
+ Pathname.new(gemspec_path) unless gemspec_path.nil?
27
+ end
28
+
20
29
  def valid?
21
30
  @errors.empty?
22
31
  end
23
32
 
24
- def suggestion
25
- Suggestion.new(lockfile_version)
33
+ def suggested_version
34
+ GemVersion.new(GemVersion.new(lockfile_version).version_string)
26
35
  end
27
36
 
28
- def suggested_definition
37
+ def suggested_definition(subject = :gemfile)
29
38
  guards = guard_versions.map { |op, version| "'#{op} #{version}'" }
30
- "gem '#{@name}', #{[suggestion, *guards].join(', ')}"
39
+ constraints = [suggested_version.suggestion, *guards].join(', ')
40
+ send(:"suggested_#{subject}_definition", constraints)
31
41
  end
32
42
 
33
43
  def definition
34
44
  versions.map do |operator, version|
35
- next t('version_not_specified') if operator == '>=' && version == '0'
45
+ next t('version_not_specified') if operator == '>=' && version.zero?
36
46
 
37
47
  "'#{operator} #{version}'"
38
48
  end.join(', ')
39
49
  end
40
50
 
41
51
  def updatable?
42
- gemfile && !suggestion.missing? && !path_source?
52
+ !valid? && !suggested_version.missing? && !path_source?
43
53
  end
44
54
 
45
55
  private
46
56
 
57
+ def gemspec_path
58
+ _spec, path = gemspec_dependency
59
+ path
60
+ end
61
+
62
+ def gemspec_spec
63
+ spec, _path = gemspec_dependency
64
+ spec
65
+ end
66
+
67
+ def gemspec_dependency
68
+ DependencyFinder.new.gemspec_dependencies.each do |path, specs|
69
+ specs.each do |spec|
70
+ return [spec, path] if spec.name == @dependency.name
71
+ end
72
+ end
73
+ nil
74
+ end
75
+
76
+ def suggested_gemspec_definition(constraints)
77
+ "add_#{gemspec_spec.type}_dependency '#{@name}', #{constraints}"
78
+ end
79
+
80
+ def suggested_gemfile_definition(constraints)
81
+ "gem '#{@name}', #{constraints}"
82
+ end
83
+
47
84
  def versions
48
85
  @dependency.requirements_list.map { |version| parse_version(version) }
49
86
  end
@@ -54,13 +91,13 @@ module StrongVersions
54
91
 
55
92
  def parse_version(requirement)
56
93
  operator, version_obj = Gem::Requirement.parse(requirement)
57
- [operator, version(version_obj)]
94
+ [operator, GemVersion.new(version_obj)]
58
95
  end
59
96
 
60
97
  def lockfile_version
61
98
  @lockfile_version ||= begin
62
99
  gem_spec = @lockfile.specs.find { |spec| spec.name == @name }
63
- gem_spec.nil? ? nil : version(gem_spec.version)
100
+ gem_spec.nil? ? nil : gem_spec.version
64
101
  end
65
102
  end
66
103
 
@@ -68,19 +105,11 @@ module StrongVersions
68
105
  Bundler::LockfileParser.new(Bundler.read_file(Bundler.default_lockfile))
69
106
  end
70
107
 
71
- def version(version_obj)
72
- # Ruby >= 2.3.0: `version_obj` is a `Gem::Version`
73
- return version_obj.version if version_obj.respond_to?(:version)
74
-
75
- # Ruby < 2.3.0: `version_obj` is a `String`
76
- version_obj
77
- end
78
-
79
108
  def validate_version(operator, version)
80
109
  return if path_source?
81
110
  return if any_valid?
82
111
 
83
- check_pessimistic(operator)
112
+ check_pessimistic(operator) unless version.zero?
84
113
  check_valid_version(version)
85
114
  end
86
115
 
@@ -91,41 +120,34 @@ module StrongVersions
91
120
  end
92
121
 
93
122
  def check_valid_version(version)
94
- return if valid_version?(version)
123
+ return if version.valid?
95
124
 
96
- value = version == '0' ? t('version_not_specified') : version
125
+ value = version.zero? ? t('version_not_specified') : version
97
126
  @errors << { type: :version, value: value }
98
127
  end
99
128
 
100
129
  def redundant?(operator, version)
101
- return false unless operator.start_with?('>') || pessimistic?(operator)
130
+ return true if pessimistic?(operator)
131
+ return false if guard_needed?(operator, version)
102
132
 
103
- multiply_version(version) <= multiply_version(suggestion.version)
133
+ true
104
134
  end
105
135
 
106
- def multiply_version(version)
107
- # Support extremely precise versions e.g. '1.2.3.4.5.6.7.8.9'
108
- components = version.split('.').map(&:to_i)
109
- components += [0] * (10 - components.size)
110
- components.reverse.each_with_index.map do |component, index|
111
- component * 10.pow(index + 1)
112
- end.sum
136
+ def guard_needed?(operator, version)
137
+ return false unless %w[< <= > >=].include?(operator)
138
+ return true if %(< <=).include?(operator) && suggested_version < version
139
+ return true if %(> >=).include?(operator) && suggested_version < version
140
+
141
+ false
113
142
  end
114
143
 
115
144
  def pessimistic?(operator)
116
145
  operator == '~>'
117
146
  end
118
147
 
119
- def valid_version?(version)
120
- return true if version =~ /^[1-9][0-9]*\.\d+$/ # major.minor, e.g. "2.5"
121
- return true if version =~ /^0\.\d+\.\d+$/ # 0.minor.patch, e.g. "0.1.8"
122
-
123
- false
124
- end
125
-
126
148
  def any_valid?
127
149
  versions.any? do |operator, version|
128
- pessimistic?(operator) && valid_version?(version)
150
+ pessimistic?(operator) && version.valid?
129
151
  end
130
152
  end
131
153
 
@@ -139,4 +161,5 @@ module StrongVersions
139
161
  I18n.t("strong_versions.#{name}")
140
162
  end
141
163
  end
164
+ # rubocop:enable Metrics/ClassLength
142
165
  end
@@ -6,6 +6,12 @@ module StrongVersions
6
6
  development + runtime
7
7
  end
8
8
 
9
+ def gemspec_dependencies
10
+ Hash[gemspecs.compact.map do |gemspec|
11
+ [gemspec.loaded_from, dependencies]
12
+ end]
13
+ end
14
+
9
15
  private
10
16
 
11
17
  def development
@@ -0,0 +1,104 @@
1
+ # frozen_string_literal: true
2
+
3
+ module StrongVersions
4
+ class GemVersion
5
+ def initialize(version)
6
+ @version = normalize(version) || ''
7
+ @parts = @version&.split('.')
8
+ end
9
+
10
+ def to_s
11
+ @version
12
+ end
13
+
14
+ def zero?
15
+ @version == '0'
16
+ end
17
+
18
+ def suggestion
19
+ return '' if version_string.empty?
20
+
21
+ "'~> #{version_string}'"
22
+ end
23
+
24
+ def version_string
25
+ return '' unless standard?
26
+
27
+ major, minor, patch = @parts
28
+ return "#{major}.#{minor}" if stable?
29
+ return "#{major}.#{minor}.#{patch}" if unstable?
30
+
31
+ raise 'Unexpected condition met'
32
+ end
33
+
34
+ def <(other)
35
+ numeric < other.numeric
36
+ end
37
+
38
+ def <=(other)
39
+ numeric <= other.numeric
40
+ end
41
+
42
+ def >(other)
43
+ numeric > other.numeric
44
+ end
45
+
46
+ def >=(other)
47
+ numeric >= other.numeric
48
+ end
49
+
50
+ def numeric
51
+ # Support extremely precise versions e.g. '1.2.3.4.5.6.7.8.9'
52
+ components = @version.split('.').map(&:to_i)
53
+ components += [0] * (10 - components.size)
54
+ components.reverse.each_with_index.map do |component, index|
55
+ component * 10.pow(index + 1)
56
+ end.sum
57
+ end
58
+
59
+ def valid?
60
+ return true if @version =~ /^[1-9][0-9]*\.\d+$/ # major.minor, e.g. "2.5"
61
+ return true if @version =~ /^0\.\d+\.\d+$/ # 0.minor.patch, e.g. "0.1.8"
62
+
63
+ false
64
+ end
65
+
66
+ def missing?
67
+ return false if stable?
68
+ return false if unstable?
69
+
70
+ true
71
+ end
72
+
73
+ private
74
+
75
+ def normalize(version)
76
+ # Ruby >= 2.3.0: `version_obj` is a `Gem::Version`
77
+ return version.version.to_s if version.respond_to?(:version)
78
+
79
+ # Ruby < 2.3.0: `version_obj` is a `String`
80
+ version
81
+ end
82
+
83
+ def unstable?
84
+ standard? && @parts.first.to_i.zero?
85
+ end
86
+
87
+ def stable?
88
+ standard? && @parts.first.to_i >= 1
89
+ end
90
+
91
+ def standard?(parts = @parts)
92
+ return false if parts.nil?
93
+ return false unless numeric?
94
+ return true if [2, 3, 4].include?(parts.size)
95
+ return true if parts.size == 3
96
+
97
+ false
98
+ end
99
+
100
+ def numeric?
101
+ @parts.all? { |part| part =~ /\A[0-9]+\Z/ }
102
+ end
103
+ end
104
+ end
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ module StrongVersions
4
+ module Regexes
5
+ class << self
6
+ def gemfile(name)
7
+ /^(\s*)gem\s+['"]#{name}['"].*$/
8
+ end
9
+
10
+ def gemspec(name)
11
+ /^(\s*[A-Za-z]+\.)add_[a-z_]*_?dependency\s*\(?\s*['"]#{name}['"].*$/
12
+ end
13
+ end
14
+ end
15
+ end
@@ -10,14 +10,14 @@ module StrongVersions
10
10
  puts(color(string, :bright, :red))
11
11
  end
12
12
 
13
- def gem_update(path, gem)
13
+ def gem_update(path, gem, subject)
14
14
  relpath = path.relative_path_from(Pathname.new(Dir.pwd))
15
15
  output = [
16
- color("[#{relpath}] ", :cyan),
17
- color(gem.suggested_definition, :green),
18
- color(' (was: ', :default),
19
- color(gem.definition, :red),
20
- color(')', :default)
16
+ color('[', :cyan),
17
+ color(relpath.to_s, :green),
18
+ color('] ', :cyan),
19
+ color('updated: ', :default),
20
+ color(gem.suggested_definition(subject), :green)
21
21
  ].join
22
22
  puts(output)
23
23
  end
@@ -77,10 +77,9 @@ module StrongVersions
77
77
  type = t("errors.#{error[:type]}")
78
78
  color(
79
79
  ' %{type} %{example}, found: %{found}',
80
- :default,
81
- type: [type, :default],
82
- example: example(error[:type]),
83
- found: [error[:value], :red]
80
+ :default, type: [type, :default],
81
+ example: example(error[:type]),
82
+ found: [error[:value], :red]
84
83
  )
85
84
  end
86
85
  end
@@ -92,10 +91,11 @@ module StrongVersions
92
91
  end
93
92
 
94
93
  def suggestion_definition(gem)
95
- unidentified = gem.suggestion.to_s.empty?
94
+ version = gem.suggested_version.suggestion
95
+ unidentified = version.empty?
96
96
  return [t('no-suggestion'), :yellow] if unidentified
97
97
 
98
- [gem.suggestion.to_s, :green]
98
+ [version, :green]
99
99
  end
100
100
 
101
101
  def name_and_definition(gem)
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module StrongVersions
4
- VERSION = '0.4.0'
4
+ VERSION = '0.4.5'
5
5
  end
@@ -28,14 +28,13 @@ Gem::Specification.new do |spec|
28
28
  # stop supporting Rails 4 we need to support I18n 0.x and 1.x. At some point,
29
29
  # I will do a release that is locked to '~> 1.0' and Rails 4 users can use
30
30
  # an older version of the gem but we are not quite there yet.
31
- spec.add_dependency 'i18n', '>= 0.5.0'
31
+ spec.add_runtime_dependency 'i18n', '>= 0.5'
32
32
  spec.add_dependency 'paint', '~> 2.0'
33
33
 
34
- spec.add_development_dependency 'betterp', '~> 0.1.2'
35
34
  spec.add_development_dependency 'bundler', '~> 1.16'
36
- spec.add_development_dependency 'byebug', '~> 10.0'
35
+ spec.add_development_dependency 'devpack', '~> 0.1.1'
37
36
  spec.add_development_dependency 'rake', '~> 10.0'
38
37
  spec.add_development_dependency 'rspec', '~> 3.0'
39
38
  spec.add_development_dependency 'rspec-its', '~> 1.2'
40
- spec.add_development_dependency 'rubocop', '~> 0.60.0'
39
+ spec.add_development_dependency 'rubocop', '~> 0.87.1'
41
40
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: strong_versions
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.0
4
+ version: 0.4.5
5
5
  platform: ruby
6
6
  authors:
7
7
  - Bob Farrell
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2020-01-25 00:00:00.000000000 Z
11
+ date: 2020-07-12 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: i18n
@@ -16,14 +16,14 @@ dependencies:
16
16
  requirements:
17
17
  - - ">="
18
18
  - !ruby/object:Gem::Version
19
- version: 0.5.0
19
+ version: '0.5'
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
24
  - - ">="
25
25
  - !ruby/object:Gem::Version
26
- version: 0.5.0
26
+ version: '0.5'
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: paint
29
29
  requirement: !ruby/object:Gem::Requirement
@@ -38,20 +38,6 @@ dependencies:
38
38
  - - "~>"
39
39
  - !ruby/object:Gem::Version
40
40
  version: '2.0'
41
- - !ruby/object:Gem::Dependency
42
- name: betterp
43
- requirement: !ruby/object:Gem::Requirement
44
- requirements:
45
- - - "~>"
46
- - !ruby/object:Gem::Version
47
- version: 0.1.2
48
- type: :development
49
- prerelease: false
50
- version_requirements: !ruby/object:Gem::Requirement
51
- requirements:
52
- - - "~>"
53
- - !ruby/object:Gem::Version
54
- version: 0.1.2
55
41
  - !ruby/object:Gem::Dependency
56
42
  name: bundler
57
43
  requirement: !ruby/object:Gem::Requirement
@@ -67,19 +53,19 @@ dependencies:
67
53
  - !ruby/object:Gem::Version
68
54
  version: '1.16'
69
55
  - !ruby/object:Gem::Dependency
70
- name: byebug
56
+ name: devpack
71
57
  requirement: !ruby/object:Gem::Requirement
72
58
  requirements:
73
59
  - - "~>"
74
60
  - !ruby/object:Gem::Version
75
- version: '10.0'
61
+ version: 0.1.1
76
62
  type: :development
77
63
  prerelease: false
78
64
  version_requirements: !ruby/object:Gem::Requirement
79
65
  requirements:
80
66
  - - "~>"
81
67
  - !ruby/object:Gem::Version
82
- version: '10.0'
68
+ version: 0.1.1
83
69
  - !ruby/object:Gem::Dependency
84
70
  name: rake
85
71
  requirement: !ruby/object:Gem::Requirement
@@ -128,14 +114,14 @@ dependencies:
128
114
  requirements:
129
115
  - - "~>"
130
116
  - !ruby/object:Gem::Version
131
- version: 0.60.0
117
+ version: 0.87.1
132
118
  type: :development
133
119
  prerelease: false
134
120
  version_requirements: !ruby/object:Gem::Requirement
135
121
  requirements:
136
122
  - - "~>"
137
123
  - !ruby/object:Gem::Version
138
- version: 0.60.0
124
+ version: 0.87.1
139
125
  description: Ensure your gems are appropriately versioned
140
126
  email:
141
127
  - oss@bob.frl
@@ -171,7 +157,8 @@ files:
171
157
  - lib/strong_versions/dependency.rb
172
158
  - lib/strong_versions/dependency_finder.rb
173
159
  - lib/strong_versions/errors.rb
174
- - lib/strong_versions/suggestion.rb
160
+ - lib/strong_versions/gem_version.rb
161
+ - lib/strong_versions/regexes.rb
175
162
  - lib/strong_versions/terminal.rb
176
163
  - lib/strong_versions/version.rb
177
164
  - strong_versions.gemspec
@@ -1,59 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module StrongVersions
4
- class Suggestion
5
- def initialize(version)
6
- return if version.nil?
7
-
8
- @parts = version.split('.')
9
- # Treat '4.3.2.1' as '4.3.2'
10
- @parts.pop if standard?(@parts.first(3)) && @parts.size == 4
11
- end
12
-
13
- def to_s
14
- return version.to_s if version.nil?
15
-
16
- "'~> #{version}'"
17
- end
18
-
19
- def version
20
- return nil unless standard?
21
-
22
- major, minor, patch = @parts
23
- return "#{major}.#{minor}" if stable?
24
- return "#{major}.#{minor}.#{patch}" if unstable?
25
-
26
- raise 'Unexpected condition met'
27
- end
28
-
29
- def missing?
30
- return false if stable?
31
- return false if unstable?
32
-
33
- true
34
- end
35
-
36
- private
37
-
38
- def unstable?
39
- standard? && @parts.first.to_i.zero?
40
- end
41
-
42
- def stable?
43
- standard? && @parts.first.to_i >= 1
44
- end
45
-
46
- def standard?(parts = @parts)
47
- return false if parts.nil?
48
- return false unless numeric?
49
- return true if [2, 3].include?(parts.size)
50
- return true if parts.size == 3 && unstable?
51
-
52
- false
53
- end
54
-
55
- def numeric?
56
- @parts.all? { |part| part =~ /\A[0-9]+\Z/ }
57
- end
58
- end
59
- end