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