module Sprout ## # Sprouts provides us with the ability to distribute source files, # precompiled libraries, and remote executables. It does all of # this by (ab)using RubyGems. # # RubyGems gives us the ability to version-manage, and distribute # arbitrary text and binary payloads. # # In order to support Flash development, we have one major problem # that RubyGems does not solve for us. This is the fact that # many elements of our executable chain are not open-source, and we do # not have the rights to directly distribute them. # # This restriction means that many of our tools and dependencies cannot be # packaged and distributed _directly_ within a RubyGem (or from # any server other than Adobe's as a matter of fact). # # In order to overcome this restriction, we have introduced # a Sprout::Specification. This is a regular Ruby file with regular # Ruby code in it. The main idea behind this file, is that it # needs to be given a name and available in your load path. # # Whenever a rake build task (Sprout::Executable) or library task, # (Sprout::Library) is encountered, it will call # Sprout::Executable.load or Sprout::Library.load (respectively). # # These methods will attempt to +require+ the provided # specification and - if it's in your load path - the specification # will be loaded, and any relevant file targets will be returned. # # There are many ways to get Ruby code into your load path. # One of the easiest to package it up in a RubyGem and # configure the +require_paths+ parameter of your Gem::Specification. # # http://docs.rubygems.org/read/chapter/20#require_paths # # To learn more about packaging RubyGems: # # http://docs.rubygems.org/read/chapter/20#page85 # http://rubygems.rubyforge.org/rdoc/Gem/Specification.html # # To learn more about published RubyGems: # # http://rubygems.org/pages/gem_docs # # To package a SWC library into a Sprout RubyGem, you would create a file (usually) # named [project_name.spec] in the root of the project. # # This is your Gem::Specification. # # You would also create a file named [projet_name.rb] and put that # into the root of the project or some other folder that you have added to # the Gem::Specification.require_paths parameter. # # == Example: Include a file directly in the RubyGem # # In the case of AsUnit, this file would be named asunit4.rb and it's contents # are as follows: # # :include:../../test/fixtures/specification/asunit4.rb # # == Example: Refer to files that are not in the RubyGem # # For projects like the Flex SDK, we can't distribute many of the required files, # so we can refer to these files in our Sprout::Specification as +remote_file_targets+. # # :include:../../test/fixtures/specification/flex4sdk.rb # # == Example: Create custom downloads for each supported platform # # For projects like the Flash Player itself, we need to refer to different # downloadable content for each supported platform. # # :include:../../test/fixtures/specification/flashplayer.rb # # == Packaging and Sharing # # Public RubyGems are hosted at http://rubygems.org. class Specification attr_accessor :name attr_accessor :version attr_reader :file_targets attr_reader :load_path ## # Create a new Sprout::Specification. # # This method will yield the new Sprout::Specification to the provided block, # and delegate most configuration parameters to a {Gem::Specification}[http://rubygems.rubyforge.org/rdoc/Gem/Specification.html]. # # To learn more about what parameters are available and/or required, please # check out RubyGems documentation for their {Gem::Specification}[http://rubygems.rubyforge.org/rdoc/Gem/Specification.html]. # def initialize filename = Sprout.file_from_caller caller.first @load_path = File.dirname filename @name = File.basename(filename).gsub('.rb', '') yield self if block_given? end ## # Add a remote file target to this RubyGem so that when it # is loaded, Sprouts will go fetch this file from the network. # # Each time this method is called, a new Sprout::RemoteFiletarget instance will be yielded to # the provided block and resolved after the block completes. # # After this block is evaluated, Sprouts will first check the collection # of env_names to see if the expected paths are available. If a valid # env_name is found, Sprouts will return the path to the requested # executable from the environment variable. # # If no env_names are set, or the requested executable is not found within # any that are identified, Sprouts will check to see if the archive # has already been unpacked into the expected location: # # #{SPROUT_HOME}/cache/#{SPROUT_VERSION}/flex4sdk/#{md5}/4.0.pre # # If the archive been unpacked, Sprouts will return the path to the # requested executable. # # If the archive has not been unpacked, Sprouts will check to see if the # archive has been downloaded to: # # #{SPROUT_HOME}/cache/#{SPROUT_VERSION}/flex4sdk/#{md5}.zip # # If the archive has been downloaded, it will be unpacked and the path # to the requested executable will be returned. # # If the archive has not been downloaded, it will be downloaded, unpacked # and the path to the requested executable will be returned. def add_remote_file_target &block target = RemoteFileTarget.new configure_target target, &block end # Add a file to the RubyGem itself. This is a great way to package smallish libraries in either # source or already-packaged form. For example, one might add a SWC to a RubyGem library. # # Each time this method is called, a new Sprout::FileTarget instance will be yielded to the # provided block, and added to a collection for packaging. # # Sprout::Specification.new do |s| # ... # s.add_file_target do |t| # t.platform = :universal # t.add_executable :asdoc, 'bin/asdoc' # end # end # def add_file_target &block target = FileTarget.new configure_target target, &block end private def configure_target t, &block t.load_path = load_path t.pkg_name = name t.pkg_version = version yield t if block_given? register_file_target_libs_and_exes t end def register_file_target_libs_and_exes target register_items target.executables, Sprout::Executable, target # Reversing the libraries makes it so that definitions like: # # target.add_library :swc, 'abcd' # target.add_library :src, 'efgh' # # When loading, if no name is specified, the :swc will be # returned to clients. register_items target.libraries, Sprout::Library, target end def register_items collection, ruby_feature, target collection.each do |exe_or_lib| exe_or_lib.pkg_name = target.pkg_name exe_or_lib.pkg_version = target.pkg_version exe_or_lib.platform = target.platform exe_or_lib.file_target = target ruby_feature.register exe_or_lib end end end end