safedep 0.1.2 → 0.2.0

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
  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