Hi,
From time to time, it is necessary to modify the gem dependencies we
ship. For example, it is good idea to remove the Mac/Windows specific
dependencies from Listen gem or sometimes it is necessary to relax some
gem dependency. Historically, we did that using sed or applying patches.
I don't think neither is optimal solution. So lately, I was thinking
about introducing macros to achieve this.
I am thinking about two macros ATM and here is their implementation:
```
%global gemspec_add_runtime_dependency() \
read -d '' add_runtime_dependency_script << 'EOR' || : \
options = %w(%{*}) \
name = options.shift \
version = [options.join(' ')] \
spec = Gem::Specification.load('.%{gem_spec}') \
dep = spec.dependencies.detect { |d| d.type == :runtime && d.name ==
name } \
if dep \
dep.requirement.concat version \
else \
spec.add_runtime_dependency name, version \
end \
File.write '.%{gem_spec}', spec.to_ruby \
EOR\
echo "$add_runtime_dependency_script" | ruby\
%{nil}
%global gemspec_remove_runtime_dependency() \
ruby \\\
-e "name = '%{1}'" \\\
-e "spec = Gem::Specification.load('.%{gem_spec}')" \\\
-e "spec.dependencies.reject! { |d| d.type == :runtime && d.name ==
name }" \\\
-e "File.write '.%{gem_spec}', spec.to_ruby" \
%{nil}
```
and you can use them as:
```
%gemspec_remove_runtime_dependency fog-dynect
%gemspec_add_runtime_dependency fog-dynect ~> 10.0
%gemspec_add_runtime_dependency fog-dynect >= 10.1
```
As you can see, both are using a bit different way of implementation.
Let me discuss the details.
The 'gemspec_remove_runtime_dependency' is using bunch of '-e'
parameters to specify the code. The advantage of this approach is, that
the build output log contains traces of the precise command which was
used, e.g.:
```
+ ruby -e 'name = '\''fog-dynect'\''' -e 'spec =
Gem::Specification.load('\''./usr/share/gems/specifications/fog-1.38.0.gemspec'\'')'
-e 'spec.dependencies.reject! { |d| d.type == :runtime && d.name == name
}' -e 'File.write
'\''./usr/share/gems/specifications/fog-1.38.0.gemspec'\'', spec.to_ruby'
```
This is helpful, but the output is not very nice and the implementation
is polluted with a lot of noise.
The other approach used in 'gemspec_add_runtime_dependency' puts the
entire script into environment variable and then pipes it into the ruby.
The log output looks like:
```
+ read -d '' add_runtime_dependency_script
+ :
+ echo 'options = %w(fog-dynect >= 10.1)
name = options.shift
version = [options.join('\'' '\'')]
spec =
Gem::Specification.load('\''./usr/share/gems/specifications/fog-1.38.0.gemspec'\'')
dep = spec.dependencies.detect { |d| d.type == :runtime && d.name ==
name }
if dep
dep.requirement.concat version
else
spec.add_runtime_dependency name, version
end
File.write '\''./usr/share/gems/specifications/fog-1.38.0.gemspec'\'',
spec.to_ruby'
+ ruby
```
Is this actually useful? Of course, the script could be piped directly
into ruby without the env variable magic, but the output is then reduced
just to:
```
+ ruby
```
which is not helpful at all (but could be improved by some hint as
"adding dependency ....").
So what is you opinion on usefulness of these macros and on the
implementation? What is the preferred way for you?
BTW this is first draft of the macros. I am going to try second
implementation, which will probably need to use a bit different syntax
for macro calls, but it might replace the 3 lines usage example above
with 2 lines version:
```
%gemspec_remove_runtime_dependency -n fog-dynect
%gemspec_add_runtime_dependency -n fog-dynect ['~> 10.0', '>= 10.1']
```
Please share your thoughts on this topic.
Vít