safedep 0.1.2 → 0.2.0

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
  SHA1:
3
- metadata.gz: d2d198c2e776fbd9a652cdf6b86cc024f8435ad2
4
- data.tar.gz: 46a70f118954452d2db915ef213b36d225bb5f54
3
+ metadata.gz: 132ffa3638720d8a67ed227359301f04ccd4e825
4
+ data.tar.gz: 9dfcd1b5e931ee79716bea0d5e967d6d034b8537
5
5
  SHA512:
6
- metadata.gz: 2f0e2df394f4d2bb542593d7279dbbf4f1941a2930519cfa7bc57054ab15c1646bddbf037daf1f43ceecb1854acec8ec53a3abb23569736d36e719af7bf6c755
7
- data.tar.gz: 622be6b932f9a390507248a268649bd8063855355ddc4fea6ed4fb40c1b6c4f88de093ac3b48787cbbea857c32f23e736b1ae5db4fa8210a006801b451451bb5
6
+ metadata.gz: b24aadff525f1c319c3c02470ceb20b731f461c908758abbd42369b39381e36a7bf513b71ea62e78ff52b7eef026f2bdd0a230a2ed28b0a8d5693e760cefe38e
7
+ data.tar.gz: 3b21b4c4e858c753a1d3e0a37dc96ab35d2c68578b946d8a0b75187a53b1dd95d79e6e57fcc8bccdc9f00cec8bef4983b1ab22ccbfbbb874c9588bc18ae64e22
@@ -56,3 +56,6 @@ GuardClause:
56
56
 
57
57
  Documentation:
58
58
  Enabled: false
59
+
60
+ SingleLineBlockParams:
61
+ Enabled: false
@@ -2,6 +2,11 @@
2
2
 
3
3
  ## Development
4
4
 
5
+ ## v0.2.0
6
+
7
+ * Skip modification of dependencies that have `:git`, `:github` or `:path` option.
8
+ * Handle depdendencies with prerelease version.
9
+
5
10
  ## v0.1.2
6
11
 
7
12
  * Handle error raised when dependency definition is not found in `Gemfile.lock`.
data/Gemfile CHANGED
@@ -14,6 +14,7 @@ group :development do
14
14
  gem 'guard-rspec', '~> 4.5'
15
15
  gem 'guard-rubocop', '~> 1.2'
16
16
  gem 'fuubar', '~> 2.0'
17
+ gem 'ruby_gntp', '~> 0.3'
17
18
  end
18
19
 
19
20
  group :test do
@@ -1,3 +1,5 @@
1
+ require 'safedep/literal'
2
+
1
3
  module Safedep
2
4
  class AbstractDependency
3
5
  attr_reader :node, :rewriter
@@ -26,19 +28,24 @@ module Safedep
26
28
  fail NotImplementedError
27
29
  end
28
30
 
29
- def version_specifier
30
- return nil unless version_specifier_node
31
- version_specifier_node.children.first
31
+ def version_specifiers
32
+ @version_specifiers ||= version_nodes.map { |node| Literal.value(node) }.flatten
32
33
  end
33
34
 
34
- def version_specifier=(version_specifier)
35
- if version_specifier_node
36
- rewriter.replace(content_range_of_str_node(version_specifier_node), version_specifier)
35
+ def version_specifiers=(*specifiers)
36
+ source = specifiers.flatten.map { |specifier| "'#{specifier}'" }.join(', ')
37
+
38
+ if version_nodes.empty?
39
+ rewriter.insert_after(name_node.loc.expression, ", #{source}")
37
40
  else
38
- rewriter.insert_after(name_node.loc.expression, ", '#{version_specifier}'")
41
+ rewriter.replace(version_range, source)
39
42
  end
40
43
  end
41
44
 
45
+ def options
46
+ {}
47
+ end
48
+
42
49
  private
43
50
 
44
51
  def method_name
@@ -49,15 +56,16 @@ module Safedep
49
56
  node.children[2]
50
57
  end
51
58
 
52
- def version_specifier_node
53
- return @version_specifier_node if instance_variable_defined?(:@version_specifier_node)
54
- version_node = node.children[3]
55
- return @version_specifier_node = nil if version_node.nil? || !version_node.str_type?
56
- @version_specifier_node = version_node
59
+ def trailing_nodes
60
+ node.children[3..-1]
61
+ end
62
+
63
+ def version_nodes
64
+ fail NotImplementedError
57
65
  end
58
66
 
59
- def options_node
60
- node.children[3..-1].find(&:hash_type?)
67
+ def version_range
68
+ version_nodes.first.loc.expression.join(version_nodes.last.loc.expression)
61
69
  end
62
70
 
63
71
  def content_range_of_str_node(str_node)
@@ -1,10 +1,11 @@
1
1
  require 'safedep/abstract_dependency'
2
+ require 'safedep/util'
2
3
  require 'astrolabe/sexp'
3
4
 
4
5
  module Safedep
5
6
  class Gemfile
6
7
  class Dependency < AbstractDependency
7
- include Astrolabe::Sexp
8
+ include Util, Astrolabe::Sexp
8
9
 
9
10
  METHOD_NAMES = [:gem].freeze
10
11
 
@@ -16,33 +17,35 @@ module Safedep
16
17
  @groups ||= (groups_via_block + groups_via_option).map(&:to_sym)
17
18
  end
18
19
 
20
+ def options
21
+ @options ||= symbolize_keys(Literal.value(options_node) || {})
22
+ end
23
+
24
+ private
25
+
19
26
  def groups_via_block
20
27
  return [] unless group_node
21
28
  _receiver_node, _message, *arg_nodes = *group_node
22
- literal_nodes = arg_nodes.select { |arg_node| arg_node.sym_type? || arg_node.str_type? }
23
- literal_nodes.map { |literal_node| literal_node.children.first }
29
+ arg_nodes.map { |node| Literal.value(node) }
24
30
  end
25
31
 
26
32
  def groups_via_option
27
- return [] unless options_node
28
-
29
- options_node.each_child_node do |pair_node|
30
- key_node, value_node = *pair_node
31
-
32
- next unless key_node == s(:sym, :group)
33
-
34
- case value_node.type
35
- when :sym
36
- return [value_node.children.first]
37
- when :array
38
- literal_nodes = value_node.each_child_node(:sym, :str)
39
- return literal_nodes.map { |literal_node| literal_node.children.first }
40
- else
41
- return []
42
- end
43
- end
33
+ Array(options[:group])
34
+ end
44
35
 
45
- []
36
+ # https://github.com/bundler/bundler/blob/v1.7.11/lib/bundler/dsl.rb#L68-L70
37
+ def version_nodes
38
+ @version_nodes ||= trailing_nodes - [options_node]
39
+ end
40
+
41
+ def options_node
42
+ node = trailing_nodes.last
43
+
44
+ if node && node.hash_type?
45
+ node
46
+ else
47
+ nil
48
+ end
46
49
  end
47
50
 
48
51
  def group_node
@@ -1,8 +1,11 @@
1
1
  require 'safedep/abstract_dependency'
2
+ require 'safedep/util'
2
3
 
3
4
  module Safedep
4
5
  class Gemspec
5
6
  class Dependency < AbstractDependency
7
+ include Util
8
+
6
9
  METHOD_NAMES = [:add_runtime_dependency, :add_development_dependency, :add_dependency].freeze
7
10
 
8
11
  def self.method_names
@@ -17,6 +20,13 @@ module Safedep
17
20
  []
18
21
  end
19
22
  end
23
+
24
+ private
25
+
26
+ # https://github.com/rubygems/rubygems/blob/v2.4.5/lib/rubygems/specification.rb#L449-L473
27
+ def version_nodes
28
+ trailing_nodes
29
+ end
20
30
  end
21
31
  end
22
32
  end
@@ -0,0 +1,48 @@
1
+ module Safedep
2
+ module Literal
3
+ module_function
4
+
5
+ def value(node)
6
+ concretize(node)
7
+ end
8
+
9
+ def concretize(node) # rubocop:disable CyclomaticComplexity
10
+ return nil unless node
11
+
12
+ case node.type
13
+ when :true then true
14
+ when :false then false
15
+ when :nil then nil
16
+ when :int, :float, :str, :sym then node.children.first
17
+ when :regexp then concretize_regexp(node)
18
+ when :array then concretize_array(node)
19
+ when :hash then concretize_hash(node)
20
+ when :irange, :erange then concretize_range(node)
21
+ end
22
+ end
23
+
24
+ def concretize_regexp(regexp_node)
25
+ str_node, *_interporated_nodes, regopt_node = *regexp_node
26
+ string = str_node.children.first
27
+ options = regopt_node.children.map(&:to_s).reduce(:+)
28
+ eval("/#{string}/#{options}") # rubocop:disable Eval
29
+ end
30
+
31
+ def concretize_array(array_node)
32
+ array_node.children.map { |child_node| concretize(child_node) }
33
+ end
34
+
35
+ def concretize_hash(hash_node)
36
+ hash_node.children.each_with_object({}) do |pair_node, hash|
37
+ key_node, value_node = *pair_node
38
+ key = concretize(key_node)
39
+ hash[key] = concretize(value_node) if key
40
+ end
41
+ end
42
+
43
+ def concretize_range(range_node)
44
+ values = range_node.children.map { |child_node| concretize(child_node) }
45
+ Range.new(*values, range_node.type == :erange)
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,52 @@
1
+ module Safedep
2
+ module Policy
3
+ class SemVer
4
+ attr_reader :version, :major, :minor, :patch, :suffix
5
+
6
+ def self.version_specifiers(version)
7
+ new(version).version_specifiers
8
+ end
9
+
10
+ def initialize(version)
11
+ @version = if version.is_a?(Gem::Version)
12
+ version
13
+ else
14
+ Gem::Version.new(version)
15
+ end
16
+
17
+ decompose_version
18
+ end
19
+
20
+ def version_specifiers
21
+ specifiers = ['~> ' + [major, minor].join('.')]
22
+ return specifiers if satisfy_specifiers?(specifiers)
23
+
24
+ specifiers = [">= #{version}", "< #{major.to_i + 1}"]
25
+ return specifiers if satisfy_specifiers?(specifiers)
26
+
27
+ nil
28
+ end
29
+
30
+ private
31
+
32
+ def decompose_version
33
+ elements = version.to_s.split('.')
34
+
35
+ [:major, :minor, :patch].each do |role|
36
+ if elements.first && elements.first.match(/^\d+$/)
37
+ instance_variable_set("@#{role}", elements.shift)
38
+ else
39
+ instance_variable_set("@#{role}", '0')
40
+ end
41
+ end
42
+
43
+ @suffix = elements.shift if elements.first && !elements.first.match(/^\d+$/)
44
+ end
45
+
46
+ def satisfy_specifiers?(specifiers)
47
+ requirement = Gem::Requirement.new(*specifiers)
48
+ requirement.satisfied_by?(version)
49
+ end
50
+ end
51
+ end
52
+ end
@@ -2,6 +2,7 @@ require 'safedep/configuration'
2
2
  require 'safedep/gemspec'
3
3
  require 'safedep/gemfile'
4
4
  require 'safedep/gemfile_lock'
5
+ require 'safedep/policy/sem_ver'
5
6
  require 'safedep/error'
6
7
 
7
8
  module Safedep
@@ -28,7 +29,7 @@ module Safedep
28
29
  'Please run `bundle install`.'
29
30
  end
30
31
 
31
- dep.version_specifier = safe_version_specifier(lockfile_dep.version)
32
+ dep.version_specifiers = version_specifiers(lockfile_dep.version)
32
33
  end
33
34
 
34
35
  gemfiles.each(&:rewrite!)
@@ -72,12 +73,13 @@ module Safedep
72
73
  end
73
74
 
74
75
  def should_ignore?(dependency)
75
- return true if dependency.version_specifier
76
- !(dependency.groups & configuration.skipped_groups).empty?
76
+ return true unless dependency.version_specifiers.empty?
77
+ return true unless (dependency.groups & configuration.skipped_groups).empty?
78
+ [:git, :github, :path].any? { |key| dependency.options[key] }
77
79
  end
78
80
 
79
- def safe_version_specifier(version)
80
- '~> ' << version.to_s.split('.').first(2).join('.')
81
+ def version_specifiers(version)
82
+ Policy::SemVer.version_specifiers(version)
81
83
  end
82
84
  end
83
85
  end
@@ -0,0 +1,16 @@
1
+ module Safedep
2
+ module Util
3
+ module_function
4
+
5
+ def symbolize_keys(original_hash)
6
+ hash = original_hash.dup
7
+
8
+ original_hash.each do |key, value|
9
+ hash[key] = symbolize_keys(value) if value.is_a?(Hash)
10
+ hash[key.to_sym] = hash.delete(key) if key.is_a?(String)
11
+ end
12
+
13
+ hash
14
+ end
15
+ end
16
+ end
@@ -2,8 +2,8 @@ module Safedep
2
2
  # http://semver.org/
3
3
  module Version
4
4
  MAJOR = 0
5
- MINOR = 1
6
- PATCH = 2
5
+ MINOR = 2
6
+ PATCH = 0
7
7
 
8
8
  def self.to_s
9
9
  [MAJOR, MINOR, PATCH].join('.')
@@ -16,6 +16,10 @@ module Safedep
16
16
  gem 'rspec', '~> 3.1'
17
17
  gem 'rubocop', require: false
18
18
  end
19
+
20
+ group :development do
21
+ gem 'guard', '>= 2.1', '< 3.0'
22
+ end
19
23
  END
20
24
 
21
25
  describe '#name' do
@@ -47,7 +51,7 @@ module Safedep
47
51
  gem 'fuubar'
48
52
  end
49
53
 
50
- gem 'rspec', group: [:test, :development]
54
+ gem 'rspec', 'group' => [:test, :development]
51
55
  END
52
56
 
53
57
  context 'when the dependency is specified in top level' do
@@ -81,34 +85,42 @@ module Safedep
81
85
  end
82
86
  end
83
87
 
84
- describe '#version_specifier' do
85
- subject(:version_specifier) { dependency.version_specifier }
88
+ describe '#version_specifiers' do
89
+ subject(:version_specifiers) { dependency.version_specifiers }
86
90
 
87
- context 'when the dependency has version specifier' do
91
+ context 'when the dependency has a version specifier' do
88
92
  let(:dependency) { gemfile.find_dependency('rspec') }
89
93
 
90
94
  it 'returns the specifier' do
91
- expect(version_specifier).to eq('~> 3.1')
95
+ expect(version_specifiers).to eq(['~> 3.1'])
96
+ end
97
+ end
98
+
99
+ context 'when the dependency has multiple specifiers' do
100
+ let(:dependency) { gemfile.find_dependency('guard') }
101
+
102
+ it 'returns the specifiers' do
103
+ expect(version_specifiers).to eq(['>= 2.1', '< 3.0'])
92
104
  end
93
105
  end
94
106
 
95
107
  context 'when the dependency has no version specifier' do
96
108
  context 'and has no options' do
97
109
  let(:dependency) { gemfile.find_dependency('rake') }
98
- it { should be_nil }
110
+ it { should be_empty }
99
111
  end
100
112
 
101
113
  context 'but has options' do
102
114
  let(:dependency) { gemfile.find_dependency('rubocop') }
103
- it { should be_nil }
115
+ it { should be_empty }
104
116
  end
105
117
  end
106
118
  end
107
119
 
108
- describe '#version_specifier=' do
120
+ describe '#version_specifiers=' do
109
121
  let(:rewritten_source) { File.read(gemfile.path) }
110
122
 
111
- context 'when the dependency has version specifier' do
123
+ context 'when the dependency has a version specifier' do
112
124
  let(:dependency) { gemfile.find_dependency('rspec') }
113
125
 
114
126
  let(:expected_source) { <<-END.strip_indent }
@@ -121,10 +133,14 @@ module Safedep
121
133
  gem 'rspec', '> 4.0'
122
134
  gem 'rubocop', require: false
123
135
  end
136
+
137
+ group :development do
138
+ gem 'guard', '>= 2.1', '< 3.0'
139
+ end
124
140
  END
125
141
 
126
142
  it 'replaces the existing specifier with the passed specifier' do
127
- dependency.version_specifier = '> 4.0'
143
+ dependency.version_specifiers = '> 4.0'
128
144
  gemfile.rewrite!
129
145
  expect(rewritten_source).to eq(expected_source)
130
146
  end
@@ -144,10 +160,14 @@ module Safedep
144
160
  gem 'rspec', '~> 3.1'
145
161
  gem 'rubocop', require: false
146
162
  end
163
+
164
+ group :development do
165
+ gem 'guard', '>= 2.1', '< 3.0'
166
+ end
147
167
  END
148
168
 
149
169
  it 'adds the passed specifier' do
150
- dependency.version_specifier = '~> 10.1'
170
+ dependency.version_specifiers = '~> 10.1'
151
171
  gemfile.rewrite!
152
172
  expect(rewritten_source).to eq(expected_source)
153
173
  end
@@ -166,15 +186,45 @@ module Safedep
166
186
  gem 'rspec', '~> 3.1'
167
187
  gem 'rubocop', '~> 0.28', require: false
168
188
  end
189
+
190
+ group :development do
191
+ gem 'guard', '>= 2.1', '< 3.0'
192
+ end
169
193
  END
170
194
 
171
195
  it 'adds the passed specifier' do
172
- dependency.version_specifier = '~> 0.28'
196
+ dependency.version_specifiers = '~> 0.28'
173
197
  gemfile.rewrite!
174
198
  expect(rewritten_source).to eq(expected_source)
175
199
  end
176
200
  end
177
201
  end
202
+
203
+ context 'when multiple specifiers are passed' do
204
+ let(:dependency) { gemfile.find_dependency('rspec') }
205
+
206
+ let(:expected_source) { <<-END.strip_indent }
207
+ source 'https://rubygems.org'
208
+
209
+ gemspec
210
+
211
+ group :development, :test do
212
+ gem 'rake'
213
+ gem 'rspec', '>= 4.0', '< 5.0'
214
+ gem 'rubocop', require: false
215
+ end
216
+
217
+ group :development do
218
+ gem 'guard', '>= 2.1', '< 3.0'
219
+ end
220
+ END
221
+
222
+ it 'replaces the existing specifier with the passed specifiers' do
223
+ dependency.version_specifiers = ['>= 4.0', '< 5.0']
224
+ gemfile.rewrite!
225
+ expect(rewritten_source).to eq(expected_source)
226
+ end
227
+ end
178
228
  end
179
229
  end
180
230
  end
@@ -10,7 +10,8 @@ module Safedep
10
10
  Gem::Specification.new do |spec|
11
11
  spec.name = 'safedep'
12
12
  spec.add_dependency 'parser'
13
- spec.add_runtime_dependency 'astrolabe', '~> 1.3'
13
+ spec.add_runtime_dependency 'bundler', '>= 1.3.1', '< 2.0'
14
+ spec.add_runtime_dependency 'astrolabe', ['>= 1.3', '< 2.0']
14
15
  spec.add_development_dependency 'rspec', '~> 3.1'
15
16
  end
16
17
  END
@@ -42,59 +43,137 @@ module Safedep
42
43
  end
43
44
  end
44
45
 
45
- describe '#version_specifier' do
46
- subject(:version_specifier) { dependency.version_specifier }
46
+ describe '#version_specifiers' do
47
+ subject(:version_specifier) { dependency.version_specifiers }
47
48
 
48
- context 'when the dependency has version specifier' do
49
+ context 'when the dependency has no version specifier' do
50
+ let(:dependency) { gemspec.find_dependency('parser') }
51
+ it { should be_empty }
52
+ end
53
+
54
+ context 'when the dependency has a version specifier' do
49
55
  let(:dependency) { gemspec.find_dependency('rspec') }
50
56
 
51
57
  it 'returns the specifier' do
52
- expect(version_specifier).to eq('~> 3.1')
58
+ expect(version_specifier).to eq(['~> 3.1'])
53
59
  end
54
60
  end
55
61
 
56
- context 'when the dependency has no version specifier' do
57
- let(:dependency) { gemspec.find_dependency('parser') }
58
- it { should be_nil }
62
+ context 'when the dependency has multiple version specifiers' do
63
+ let(:dependency) { gemspec.find_dependency('bundler') }
64
+
65
+ it 'returns the specifiers' do
66
+ expect(version_specifier).to eq(['>= 1.3.1', '< 2.0'])
67
+ end
68
+ end
69
+
70
+ context 'when the dependency has multiple version specifiers in an array' do
71
+ let(:dependency) { gemspec.find_dependency('astrolabe') }
72
+
73
+ it 'returns the specifiers' do
74
+ expect(version_specifier).to eq(['>= 1.3', '< 2.0'])
75
+ end
59
76
  end
60
77
  end
61
78
 
62
- describe '#version_specifier=' do
79
+ describe '#version_specifiers=' do
63
80
  let(:rewritten_source) { File.read(gemspec.path) }
64
81
 
65
- context 'when the dependency has version specifier' do
82
+ context 'when the dependency has no version specifier' do
83
+ let(:dependency) { gemspec.find_dependency('parser') }
84
+
85
+ let(:expected_source) { <<-END.strip_indent }
86
+ Gem::Specification.new do |spec|
87
+ spec.name = 'safedep'
88
+ spec.add_dependency 'parser', '~> 2.2'
89
+ spec.add_runtime_dependency 'bundler', '>= 1.3.1', '< 2.0'
90
+ spec.add_runtime_dependency 'astrolabe', ['>= 1.3', '< 2.0']
91
+ spec.add_development_dependency 'rspec', '~> 3.1'
92
+ end
93
+ END
94
+
95
+ it 'adds the passed specifier' do
96
+ dependency.version_specifiers = '~> 2.2'
97
+ gemspec.rewrite!
98
+ expect(rewritten_source).to eq(expected_source)
99
+ end
100
+ end
101
+
102
+ context 'when the dependency has a version specifier' do
66
103
  let(:dependency) { gemspec.find_dependency('rspec') }
67
104
 
68
105
  let(:expected_source) { <<-END.strip_indent }
69
106
  Gem::Specification.new do |spec|
70
107
  spec.name = 'safedep'
71
108
  spec.add_dependency 'parser'
72
- spec.add_runtime_dependency 'astrolabe', '~> 1.3'
109
+ spec.add_runtime_dependency 'bundler', '>= 1.3.1', '< 2.0'
110
+ spec.add_runtime_dependency 'astrolabe', ['>= 1.3', '< 2.0']
73
111
  spec.add_development_dependency 'rspec', '> 4.0'
74
112
  end
75
113
  END
76
114
 
77
115
  it 'replaces the existing specifier with the passed specifier' do
78
- dependency.version_specifier = '> 4.0'
116
+ dependency.version_specifiers = '> 4.0'
79
117
  gemspec.rewrite!
80
118
  expect(rewritten_source).to eq(expected_source)
81
119
  end
82
120
  end
83
121
 
84
- context 'when the dependency has no version specifier' do
85
- let(:dependency) { gemspec.find_dependency('parser') }
122
+ context 'when the dependency has multiple version specifiers' do
123
+ let(:dependency) { gemspec.find_dependency('bundler') }
86
124
 
87
125
  let(:expected_source) { <<-END.strip_indent }
88
126
  Gem::Specification.new do |spec|
89
127
  spec.name = 'safedep'
90
- spec.add_dependency 'parser', '~> 2.2'
91
- spec.add_runtime_dependency 'astrolabe', '~> 1.3'
128
+ spec.add_dependency 'parser'
129
+ spec.add_runtime_dependency 'bundler', '~> 2.0'
130
+ spec.add_runtime_dependency 'astrolabe', ['>= 1.3', '< 2.0']
92
131
  spec.add_development_dependency 'rspec', '~> 3.1'
93
132
  end
94
133
  END
95
134
 
96
- it 'adds the passed specifier' do
97
- dependency.version_specifier = '~> 2.2'
135
+ it 'replaces the existing specifiers with the passed specifier' do
136
+ dependency.version_specifiers = '~> 2.0'
137
+ gemspec.rewrite!
138
+ expect(rewritten_source).to eq(expected_source)
139
+ end
140
+ end
141
+
142
+ context 'when the dependency has multiple version specifiers in an array' do
143
+ let(:dependency) { gemspec.find_dependency('astrolabe') }
144
+
145
+ let(:expected_source) { <<-END.strip_indent }
146
+ Gem::Specification.new do |spec|
147
+ spec.name = 'safedep'
148
+ spec.add_dependency 'parser'
149
+ spec.add_runtime_dependency 'bundler', '>= 1.3.1', '< 2.0'
150
+ spec.add_runtime_dependency 'astrolabe', '~> 2.0'
151
+ spec.add_development_dependency 'rspec', '~> 3.1'
152
+ end
153
+ END
154
+
155
+ it 'replaces the existing specifiers with the passed specifier' do
156
+ dependency.version_specifiers = '~> 2.0'
157
+ gemspec.rewrite!
158
+ expect(rewritten_source).to eq(expected_source)
159
+ end
160
+ end
161
+
162
+ context 'when multiple specifiers are passed' do
163
+ let(:dependency) { gemspec.find_dependency('rspec') }
164
+
165
+ let(:expected_source) { <<-END.strip_indent }
166
+ Gem::Specification.new do |spec|
167
+ spec.name = 'safedep'
168
+ spec.add_dependency 'parser'
169
+ spec.add_runtime_dependency 'bundler', '>= 1.3.1', '< 2.0'
170
+ spec.add_runtime_dependency 'astrolabe', ['>= 1.3', '< 2.0']
171
+ spec.add_development_dependency 'rspec', '>= 3.1', '< 4.0'
172
+ end
173
+ END
174
+
175
+ it 'replaces the existing specifier with the passed specifier' do
176
+ dependency.version_specifiers = ['>= 3.1', '< 4.0']
98
177
  gemspec.rewrite!
99
178
  expect(rewritten_source).to eq(expected_source)
100
179
  end
@@ -0,0 +1,49 @@
1
+ require 'safedep/literal'
2
+ require 'astrolabe/builder'
3
+ require 'parser/current'
4
+
5
+ module Safedep
6
+ describe Literal do
7
+ let(:node) do
8
+ builder = Astrolabe::Builder.new
9
+ parser = Parser::CurrentRuby.new(builder)
10
+ parser.parse(source_buffer)
11
+ end
12
+
13
+ let(:source_buffer) do
14
+ Parser::Source::Buffer.new('(string)').tap do |buffer|
15
+ buffer.source = source
16
+ end
17
+ end
18
+
19
+ describe '.value' do
20
+ subject { Literal.value(node) }
21
+
22
+ [
23
+ true,
24
+ false,
25
+ nil,
26
+ 123,
27
+ 3.14,
28
+ 'foo',
29
+ :foo,
30
+ /foo/im,
31
+ ['foo', 123],
32
+ { 'foo' => 123, bar: false },
33
+ 1..3,
34
+ 1...3,
35
+ { 'foo' => [:bar, { baz: 3.14 }] }
36
+ ].each do |value|
37
+ context "with #{value.inspect} node" do
38
+ let(:source) { value.inspect }
39
+ it { should eq(value) }
40
+ end
41
+ end
42
+
43
+ context 'when nil is passed' do
44
+ let(:node) { nil }
45
+ it { should be_nil }
46
+ end
47
+ end
48
+ end
49
+ end
@@ -0,0 +1,35 @@
1
+ require 'safedep/policy/sem_ver'
2
+
3
+ module Safedep
4
+ module Policy
5
+ describe SemVer do
6
+ describe '.version_specifiers' do
7
+ subject { SemVer.version_specifiers(version) }
8
+
9
+ [
10
+ ['0.0.1', ['~> 0.0']],
11
+ ['1.2.34', ['~> 1.2']],
12
+ ['1.2', ['~> 1.2']],
13
+ ['1', ['~> 1.0']],
14
+ ['1.2.1.beta1', ['~> 1.2']],
15
+ ['1.2.0.beta1', ['>= 1.2.0.beta1', '< 2']],
16
+ ['1.2.beta1', ['>= 1.2.beta1', '< 2']],
17
+ ['1.beta1', ['>= 1.beta1', '< 2']]
18
+ ].each do |version_string, specifiers|
19
+ context "with #{version_string}" do
20
+ let(:version) { Gem::Version.new(version_string) }
21
+ let(:requirement) { Gem::Requirement.new(*specifiers) }
22
+
23
+ it { should eq(specifiers) }
24
+
25
+ if specifiers
26
+ it 'returns version specifiers satisfied by the passed version' do
27
+ expect(requirement).to be_satisfied_by(version)
28
+ end
29
+ end
30
+ end
31
+ end
32
+ end
33
+ end
34
+ end
35
+ end
@@ -83,11 +83,56 @@ module Safedep
83
83
 
84
84
  it 'does not modify dependencies that belong to any of the groups' do
85
85
  development_dependencies.each do |dep|
86
- expect(dep).not_to receive(:version_specifier=)
86
+ expect(dep).not_to receive(:version_specifiers=)
87
87
  end
88
88
 
89
89
  runner.run
90
90
  end
91
91
  end
92
+
93
+ context 'when a dependency has :git option', :gemfile, :lockfile do
94
+ let(:gemfile_source) { <<-END.strip_indent }
95
+ source 'https://rubygems.org'
96
+
97
+ group :development, :test do
98
+ gem 'rubocop', git: 'https://github.com/bbatsov/rubocop.git'
99
+ end
100
+ END
101
+
102
+ it 'does not add version specifiers to the dependency' do
103
+ runner.run
104
+ expect(rewritten_gemfile_source).to eq(gemfile_source)
105
+ end
106
+ end
107
+
108
+ context 'when a dependency has :github option', :gemfile, :lockfile do
109
+ let(:gemfile_source) { <<-END.strip_indent }
110
+ source 'https://rubygems.org'
111
+
112
+ group :development, :test do
113
+ gem 'rubocop', github: 'bbatsov/rubocop.git'
114
+ end
115
+ END
116
+
117
+ it 'does not add version specifiers to the dependency' do
118
+ runner.run
119
+ expect(rewritten_gemfile_source).to eq(gemfile_source)
120
+ end
121
+ end
122
+
123
+ context 'when a dependency has :path option', :gemfile, :lockfile do
124
+ let(:gemfile_source) { <<-END.strip_indent }
125
+ source 'https://rubygems.org'
126
+
127
+ group :development, :test do
128
+ gem 'rubocop', path: '../rubocop'
129
+ end
130
+ END
131
+
132
+ it 'does not add version specifiers to the dependency' do
133
+ runner.run
134
+ expect(rewritten_gemfile_source).to eq(gemfile_source)
135
+ end
136
+ end
92
137
  end
93
138
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: safedep
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.2
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Yuji Nakayama
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-01-10 00:00:00.000000000 Z
11
+ date: 2015-01-11 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: parser
@@ -82,7 +82,10 @@ files:
82
82
  - lib/safedep/gemfile_lock.rb
83
83
  - lib/safedep/gemspec.rb
84
84
  - lib/safedep/gemspec/dependency.rb
85
+ - lib/safedep/literal.rb
86
+ - lib/safedep/policy/sem_ver.rb
85
87
  - lib/safedep/runner.rb
88
+ - lib/safedep/util.rb
86
89
  - lib/safedep/version.rb
87
90
  - safedep.gemspec
88
91
  - spec/.rubocop.yml
@@ -92,6 +95,8 @@ files:
92
95
  - spec/safedep/gemfile_spec.rb
93
96
  - spec/safedep/gemspec/dependency_spec.rb
94
97
  - spec/safedep/gemspec_spec.rb
98
+ - spec/safedep/literal_spec.rb
99
+ - spec/safedep/policy/sem_ver_spec.rb
95
100
  - spec/safedep/runner_spec.rb
96
101
  - spec/spec_helper.rb
97
102
  - spec/support/file_helper.rb
@@ -128,6 +133,8 @@ test_files:
128
133
  - spec/safedep/gemfile_spec.rb
129
134
  - spec/safedep/gemspec/dependency_spec.rb
130
135
  - spec/safedep/gemspec_spec.rb
136
+ - spec/safedep/literal_spec.rb
137
+ - spec/safedep/policy/sem_ver_spec.rb
131
138
  - spec/safedep/runner_spec.rb
132
139
  - spec/spec_helper.rb
133
140
  - spec/support/file_helper.rb