strong_versions 0.4.0 → 0.4.5

Sign up to get free protection for your applications and to get access to all the features.
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