# Build a ruby gem and conditionally specify dependencies

**URL:** <https://www.ruby-forum.com/t/build-a-ruby-gem-and-conditionally-specify-dependencies/215953>\
**Category:** Rails\
**Created:** [January 20, 2012, 11:58am UTC](https://www.ruby-forum.com/t/build-a-ruby-gem-and-conditionally-specify-dependencies/215953 "2012-01-20T11:58:25Z")\
**Posts on this page:** 3\
**Page:** 1

<div class="post-metadata">

**Author:** ![luislavena](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/l/0ea827/32.png) [@luislavena](https://www.ruby-forum.com/u/luislavena)\
**Post date:** [January 20, 2012, 11:58am UTC](https://www.ruby-forum.com/t/build-a-ruby-gem-and-conditionally-specify-dependencies/215953/1 "2012-01-20T11:58:25Z")

</div>

I am working on a gem that has needs to set dependencies conditionally  
when the gem is installed. I’ve done some digging around

and it looks like i’m not alone in this need.

> <https://stackoverflow.com/questions/4596606/rubygems-how-do-i-add-platform-specific-dependency>

# this is a long thread

[http://www.ruby-forum.com/topic/957999](http://www.ruby-forum.com/topic/957999)

The only way I can see to add dependencies to a gem is to use  
add\_dependency method within a Gem::Specifiction block in a .gemspec  
file

Gem::Specification.new do |s|

# … standard setup stuff

# conditionally set dependencies

s.add\_dependency “rb-inotify”, “~\> 0.8.8” if RUBY\_PLATFORM =~ /linux/  
i  
s.add\_dependency “rb-fsevent”, “~\> 0.4.3.1” if RUBY\_PLATFORM =~ /  
darwin/i  
s.add\_dependency “rb-fchange”, “~\> 0.0.5” if RUBY\_PLATFORM =~ /mswin|  
mingw/i

end

Based on all of the docs and threads I found on the net, I would have  
expected that if you install the gem on

- Linux, then, rb-inotify would be a dependency and auto-installed
- Mac - rb-fsevent would be installed
- Windows - rb-fchange would be installed

However, it seems that is not the case. The “if” statements within  
the block are evaluated at the time the gem is built and packaged.  
Therefore,  
if you build and package the gem on Linux, then, rb-inotify is added  
as a dependency, Mac, then, rb-fsevent, Windows - rb-fchange.

Still needing a solution, I dug around in the rubygems code and it  
seems the following is a broad stoke of what happens.

- build all of your code for your gem: foo.gem
- create a foo.gemspec file
- build, package, and release the gem to a gem server such as  
[rubygems.org](http://rubygems.org)
- let everyone know
- developers install it locally via: gem install foo
- the foo.gem file is downloaded, unpacked, and installed. all  
dependencies are installed as well.
- everything should be set and we can beging using the gem.

It seems that when the gem is built and released the foo.gemspec file  
is loaded and the Gem::Specification block is evaluated and converted  
to YAML, compressed as  
metadata.gz, and included in foo.gem. The ruby code is compressed  
into data.tar.gz and included as well. When the gem is installed on  
the local developer machine,  
the YAML is extracted from metadata.gz and converted back into a  
Gem::Specification block, however, it is not converted back to the  
original block.

instead, you will see something like the following:

Gem::Specification.new do |s|

if s.respond\_to? :specification\_version then  
s.specification\_version = 3

```
if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0')

```

then  
s.add\_runtime\_dependency(%q, [“~\> 0.8.8”])  
else  
s.add\_dependency(%q, [“~\> 0.8.8”])  
end  
else  
s.add\_dependency(%q, [“~\> 0.8.8”])  
end

end

Ok. So, I have a bird’s eye view of the process, however, that does  
not change my desire to build a single gem and conditionally specify  
dependencies for a range of OS targets.

If anyone has a solution other than building multiple .gemspec files  
for each target OS… I’m all ears!!

---

<div class="post-metadata">

**Author:** ![resident\_moron](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/r/5daacb/32.png) [@resident\_moron](https://www.ruby-forum.com/u/resident_moron)\
**Post date:** [January 20, 2012, 3:12pm UTC](https://www.ruby-forum.com/t/build-a-ruby-gem-and-conditionally-specify-dependencies/215953/2 "2012-01-20T15:12:17Z")

</div>

On Jan 20, 7:56am, “rails.impaired” [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid) wrote:

> add\_dependency method within a Gem::Specifiction block in a .gemspec  
> file

You can’t use conditionals on gemspec because gemspec is serialized  
into YAML, which doesn’t contain executable code.

The recommendation is to generate the gemspec and change both platform  
and dependencies for each platform:

gemspec = Gem::Specification.new do |s|  
s.platform = Gem::Platform::RUBY  
end

# here build the normal gem

# Now for linux:

gemspec.platform = “linux”  
gemspec.add\_dependency …

# build the newer gemspec

…

> Ok. So, I have a bird’s eye view of the process, however, that does  
> not change my desire to build a single gem and conditionally specify  
> dependencies for a range of OS targets.

Well, is not possible, dependencies are defined for the gemspec, can’t  
be defined for different platforms.

Probably you can introduce a newer version of the gemspec for RubyGems  
2.0…

> If anyone has a solution other than building multiple .gemspec files  
> for each target OS… I’m all ears!!

Above example has been used in different projects, most of the time by  
#dup the gemspec and building it for each platform.

–  
Luis L.

---

<div class="post-metadata">

**Author:** ![resident\_moron](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/r/5daacb/32.png) [@resident\_moron](https://www.ruby-forum.com/u/resident_moron)\
**Post date:** [January 20, 2012, 3:27pm UTC](https://www.ruby-forum.com/t/build-a-ruby-gem-and-conditionally-specify-dependencies/215953/3 "2012-01-20T15:27:47Z")

</div>

On Fri, Jan 20, 2012 at 3:10 PM, Luis L. [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid)  
wrote:

> On Jan 20, 7:56 am, “rails.impaired” [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid) wrote:\>

…

> > If anyone has a solution other than building multiple .gemspec files  
> > for each target OS… I’m all ears!!
> 
> Above example has been used in different projects, most of the time by  
> #dup the gemspec and building it for each platform.

We face a related problem in the Gemfile of a local Rails project (not a  
gem).

Currently, the Gemfile contains:

group :test do  
…

# on Mac os X

gem ‘rb-fsevent’ if RUBY\_PLATFORM.include?(“x86\_64-darwin”)  
gem ‘ruby\_gntp’ if RUBY\_PLATFORM.include?(“x86\_64-darwin”)

# on Linux

gem ‘rb-inotify’ unless RUBY\_PLATFORM.include?(“x86\_64-darwin”)  
gem ‘libnotify’ unless RUBY\_PLATFORM.include?(“x86\_64-darwin”)  
end

This works (although it is ugly) for developing on Mac and Linux  
systems.

But, we stopped checking in the Gemfile.lock since it changes every time  
a developer with a different platform checks in the code.

So, a solution for multi-platform Gemfiles should also solve the  
problem for Gemfile.lock.

Or is there a solution that we overlooked?

Thanks,

Peter
