rails.impaired
2012-Jan-20 10:56 UTC
Build a ruby gem and conditionally specify dependencies
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. http://stackoverflow.com/questions/4596606/rubygems-how-do-i-add-platform-specific-dependency # this is a long thread 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 - 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<rb-inotify>, ["~> 0.8.8"]) else s.add_dependency(%q<rb-inotify>, ["~> 0.8.8"]) end else s.add_dependency(%q<rb-inotify>, ["~> 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!! -- You received this message because you are subscribed to the Google Groups "Ruby on Rails: Talk" group. To post to this group, send email to rubyonrails-talk-/JYPxA39Uh5TLH3MbocFF+G/Ez6ZCGd0@public.gmane.org To unsubscribe from this group, send email to rubyonrails-talk+unsubscribe-/JYPxA39Uh5TLH3MbocFF+G/Ez6ZCGd0@public.gmane.org For more options, visit this group at http://groups.google.com/group/rubyonrails-talk?hl=en.
Luis Lavena
2012-Jan-20 14:10 UTC
Re: Build a ruby gem and conditionally specify dependencies
On Jan 20, 7:56 am, "rails.impaired" <resident.mo...-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> wrote:> 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. > > http://stackoverflow.com/questions/4596606/rubygems-how-do-i-add-plat... > > # this is a long threadhttp://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 >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 Lavena -- You received this message because you are subscribed to the Google Groups "Ruby on Rails: Talk" group. To post to this group, send email to rubyonrails-talk-/JYPxA39Uh5TLH3MbocFF+G/Ez6ZCGd0@public.gmane.org To unsubscribe from this group, send email to rubyonrails-talk+unsubscribe@googlegroups.com. For more options, visit this group at http://groups.google.com/group/rubyonrails-talk?hl=en.
Peter Vandenabeele
2012-Jan-20 14:26 UTC
Re: Re: Build a ruby gem and conditionally specify dependencies
On Fri, Jan 20, 2012 at 3:10 PM, Luis Lavena <luislavena-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> wrote:> On Jan 20, 7:56 am, "rails.impaired" <resident.mo...-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> wrote:> >...> > 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. >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 -- You received this message because you are subscribed to the Google Groups "Ruby on Rails: Talk" group. To post to this group, send email to rubyonrails-talk-/JYPxA39Uh5TLH3MbocFF+G/Ez6ZCGd0@public.gmane.org To unsubscribe from this group, send email to rubyonrails-talk+unsubscribe-/JYPxA39Uh5TLH3MbocFF+G/Ez6ZCGd0@public.gmane.org For more options, visit this group at http://groups.google.com/group/rubyonrails-talk?hl=en.